当使用seek和调用next()读取文件时,有没有一种方法可以返回?

问题描述 投票:4回答:2

我正在写一个Python脚本来读取一个文件,当我到达文件的某一节时,最终读取该节中那些行的方式取决于该节中也给出的信息。所以我发现 此处 我可以用这样的东西

fp = open('myfile')
last_pos = fp.tell()
line = fp.readline()
while line != '':
  if line == 'SPECIAL':
  fp.seek(last_pos)
  other_function(fp)
  break
last_pos = fp.tell()
line = fp.readline()

然而,我现在的代码结构是这样的。

fh = open(filename)

# get generator function and attach None at the end to stop iteration
items = itertools.chain(((lino,line) for lino, line in enumerate(fh, start=1)), (None,))
item = True

  lino, line = next(items)

  # handle special section
  if line.startswith['SPECIAL']:

    start = fh.tell()

    for i in range(specialLines):
      lino, eline = next(items)
      # etc. get the special data I need here

    # try to set the pointer to start to reread the special section  
    fh.seek(start)

    # then reread the special section

但这种方法给出了以下错误:

通过调用next()告诉位置禁用

有什么办法可以防止这种情况的发生吗?

python python-3.x next seek tell
2个回答
6
投票

将文件作为迭代器使用 (例如调用 next() 上或用在 for 循环)使用的是内部缓冲区;实际的文件读取位置在文件的更远处,使用 .tell() 不会给你下一行的位置让步。

如果你需要来回寻找,解决的办法是不使用 next() 直接在文件对象上,但使用 file.readline() 仅仅是。你仍然可以使用迭代器来实现,使用两个参数版本的 iter():

fileobj = open(filename)
fh = iter(fileobj.readline, '')

呼叫 next() 关于 fileiterator() 将调用 fileobj.readline() 直到该函数返回一个空字符串。实际上,这就创建了一个文件迭代器,这个迭代器会在 使用内部缓冲区。

演示。

>>> fh = open('example.txt')
>>> fhiter = iter(fh.readline, '')
>>> next(fhiter)
'foo spam eggs\n'
>>> fh.tell()
14
>>> fh.seek(0)
0
>>> next(fhiter)
'foo spam eggs\n'

请注意,你的 enumerate 链可以简化为。

items = itertools.chain(enumerate(fh, start=1), (None,))

虽然我不知道你为什么会认为... (None,) 这里需要哨兵。StopIteration 仍然会被提拔,尽管多了一个 next() 稍后再打。

要阅读 specialLines 计行 itertools.islice():

for lino, eline in islice(items, specialLines):
    # etc. get the special data I need here

你可以直接在上面循环 fh 而不是使用无限循环和 next() 这里也有电话。

with open(filename) as fh:
    enumerated = enumerate(iter(fileobj.readline, ''), start=1):
    for lino, line in enumerated:
        # handle special section
        if line.startswith['SPECIAL']:
            start = fh.tell()

            for lino, eline in islice(items, specialLines):
                # etc. get the special data I need here

            fh.seek(start)

但请注意,你的行号仍然会递增,甚至当你回溯时也是如此。

然而,你可能想要重构你的代码,以避免重新读取文件的部分。


0
投票

我不是Python第3版的专家,但看起来你是在使用 generatoryields 从文件中读取的行。因此你只能有单边的方向。

你必须使用另一种方法。

© www.soinside.com 2019 - 2024. All rights reserved.