【问题标题】:Is there a way to go back when reading a file using seek and calls to next()?使用 seek 和调用 next() 读取文件时,有没有办法返回?
【发布时间】:2014-05-06 11:29:43
【问题描述】:

我正在编写一个 Python 脚本来读取文件,当我到达文件的某个部分时,读取该部分中这些行的最终方法取决于该部分中提供的信息。所以我发现here 我可以使用类似的东西

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


    【解决方案1】:

    将文件用作迭代器(例如在其上调用next() 或在for 循环中使用它)使用内部缓冲区;实际文件读取位置在文件中更远,使用 .tell() 不会为您提供下一行的位置。

    如果需要来回查找,解决方法不是直接在文件对象上使用next(),而是只使用file.readline()。您仍然可以为此使用迭代器,使用 iter() 的两个参数版本:

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

    fileiterator() 上调用next() 将调用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)
    

    但请注意,即使您回溯,您的行号仍会增加!

    但是,您可能希望重构代码以不需要重新读取文件的某些部分。

    【讨论】:

    • 谢谢@Martijn。获取行号的枚举器调用也会发生什么?
    • @AlejandroMarcosAragon:你对chain() 的使用有点……奇怪,但它会起作用。
    • 我必须在最后添加 None ,否则当我到达文件末尾时会出现 StopIteration 异常。我仍然无法让 iter 为 lino 枚举。
    • @AlejandroMarcosAragon:你可以要求next()在你到达终点时返回Nonenext(items, None)。您似乎遇到了一个错误,因为您所做的只是将StopIteration 再推迟一个电话。
    • 更少的循环,更少的 I/O。
    【解决方案2】:

    我不是 Python 版本 3 的专家,但您似乎正在使用 generator 读取从文件中读取的 yields 行。因此你只能有一个方向。

    您将不得不使用另一种方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-27
      • 1970-01-01
      • 1970-01-01
      • 2013-09-25
      相关资源
      最近更新 更多