Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Undo a file readline() operation so file-pointer is back in original state

I'm browsing through a Python file pointer of a text file in read-only mode using file.readline() looking for a special line. Once I find that line I want to pass the file pointer to a method that is expecting the file pointer to be at the START of that readline (not right after it.)

How do I essentially undo one file.readline() operation on a file pointer?

like image 371
MikeN Avatar asked Aug 17 '10 18:08

MikeN


People also ask

What does readline () method return?

The readlines() method returns a list containing each line in the file as a list item.

What will some file readline () return?

The readlines() function reads till the End of the file making use of readline() function internally and returns a list that has all the lines read from the file. It is possible to read a file line by line using for loop. To do that, first, open the file using Python open() function in read mode.

Does readline () return a string?

The readline method reads one line from the file and returns it as a string. The string returned by readline will contain the newline character at the end.

How do I move a pointer to a previous line in Python?

Learn to use the seek() method to move the file cursor ahead or backward from the current position. Learn to move the file pointer to that start or end of the file. Learn to move the file pointer backward from the end of the file. Get the current position of the file handle.


4 Answers

You have to remember the position by calling file.tell() before the readline and then calling file.seek() to rewind. 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()

I can't recall if it is safe to call file.seek() inside of a for line in file loop so I usually just write out the while loop. There is probably a much more pythonic way of doing this.

like image 175
D.Shawley Avatar answered Oct 05 '22 23:10

D.Shawley


You record the starting point of the line with thefile.tell() before you call readline, and get back to that point, if you need to, with thefile.seek.

>>> with open('bah.txt', 'w') as f:
...   f.writelines('Hello %s\n' % i for i in range(5))
... 
>>> with open('bah.txt') as f:
...   f.readline()
...   x = f.tell()
...   f.readline()
...   f.seek(x)
...   f.readline()
... 
'Hello 0\n'
'Hello 1\n'
'Hello 1\n'
>>> 

as you see, the seek/tell "pair" is "undoing", so to speak, the file pointer movement performed by readline. Of course, this can only work on an actual seekable (i.e., disk) file, not (e.g.) on file-like objects built w/the makefile method of sockets, etc etc.

like image 31
Alex Martelli Avatar answered Oct 06 '22 00:10

Alex Martelli


If your method simply wants to iterate through the file, then you could use itertools.chain to make an appropriate iterator:

import itertools

# do something to the marker line and everything after
def process(it):
    for line in it:
        print line,
        
with open(filename,'r') as f:
    for line in f:
        if 'marker' in line:
            it=itertools.chain((line,),f)
            process(it)
            break
like image 42
unutbu Avatar answered Oct 05 '22 22:10

unutbu


fin = open('myfile')
for l in fin:
    if l == 'myspecialline':
        # Move the pointer back to the beginning of this line
        fin.seek(fin.tell() - len(l))
        break
# now fin points to the start of your special line
like image 20
GWW Avatar answered Oct 05 '22 22:10

GWW