Есть ли способ вернуться назад при чтении файла с помощью поиска и вызова 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
строки, которые читаются из файла. Таким образом, вы можете иметь только одностороннее направление.
Вам придется использовать другой подход.