Python: deshace una operación readline () del archivo para que el puntero del archivo vuelva a su estado original

Estoy navegando a través de un puntero de archivo Python de un archivo de texto en modo de solo lectura usando file.readline () buscando una línea especial. Una vez que encuentro esa línea, quiero pasar el puntero del archivo a un método que espera que el puntero del archivo esté en el INICIO de esa línea de lectura (no inmediatamente después).

¿Cómo esencialmente deshago una operación file.readline () en un puntero de archivo?

file.tell() recordar la posición llamando a file.tell() antes de la línea de lectura y luego llamando a file.seek() para rebobinar. Algo como:

 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() 

No puedo recordar si es seguro llamar a file.seek() dentro de un bucle for line in file bucle de for line in file por lo que normalmente escribo el bucle while. Probablemente hay una forma mucho más pythonica de hacer esto.

thefile.tell() el punto de inicio de la línea con thefile.tell() antes de llamar a readline , y vuelva a ese punto, si es necesario, con 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' >>> 

Como ve, el “par” de buscar / decir es “deshacer”, por así decirlo, el movimiento del puntero del archivo realizado por readline . Por supuesto, esto solo puede funcionar en un archivo de búsqueda real (es decir, disco), no (por ejemplo) en objetos tipo archivo construidos con el método de sockets de makefile, etc.

Si su método simplemente quiere iterar a través del archivo, entonces podría usar itertools.chain para hacer un iterador apropiado:

 import itertools 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 
 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 

Si no conoce la última línea porque no la visitó, puede leer hacia atrás hasta que vea un carácter de nueva línea:

 with open(logfile, 'r') as f: # go to EOF f.seek(0, os.SEEK_END) nlines = f.tell() i=0 while True: f.seek(nlines-i) char = f.read(1) if char=='\n': break i+=1