Есть ли способ вернуться назад при чтении файла с помощью поиска и вызова next()?

Я пишу сценарий 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

Но такой подход дает следующую ошибку:

telling position disabled by next() call

Есть ли способ предотвратить это? Лучший.

2 ответа

Решение

Использование файла в качестве итератора (например, вызов next() на нем или используя его в for loop) использует внутренний буфер; фактическая позиция чтения файла находится дальше вдоль файла и с использованием .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)

но учтите, что номера ваших строк будут увеличиваться даже при поиске назад!

Однако вы, вероятно, хотите реорганизовать свой код, чтобы не нужно было перечитывать разделы вашего файла.

Я не эксперт с версией 3 Python, но кажется, что вы читаете, используя generator тот yields строки, которые читаются из файла. Таким образом, вы можете иметь только одностороннее направление.

Вам придется использовать другой подход.

Другие вопросы по тегам