I'm writing a Python script to read a file, and when I arrive at a section of the file, the final way to read those lines in the section depends on information that's given also in that section. So I found here that I could use something like
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()
Yet, the structure of my current code is something like the following:
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
But this approach gives the following error:
telling position disabled by next() call
Is there a way to prevent this?
Using the file as an iterator (such as calling
next()
on it or using it in afor
loop) uses an internal buffer; the actual file read position is further along the file and using.tell()
will not give you the position of the next line to yield.If you need to seek back and forth, the solution is not to use
next()
directly on the file object but usefile.readline()
only. You can still use an iterator for that, use the two-argument version ofiter()
:Calling
next()
onfileiterator()
will invokefileobj.readline()
until that function returns an empty string. In effect, this creates a file iterator that doesn't use the internal buffer.Demo:
Note that your
enumerate
chain can be simplified to:although I am in the dark why you think a
(None,)
sentinel is needed here;StopIteration
will still be raised, albeit one morenext()
call later.To read
specialLines
count lines, useitertools.islice()
:You can just loop directly over
fh
instead of using an infinite loop andnext()
calls here too:but do note that your line numbers will still increment even when you seek back!
You probably want to refactor your code to not need to re-read sections of your file, however.