Python: Deshacer una operación de archivo readline () de modo puntero a fichero está de vuelta en su estado original
Pregunta
Estoy navegando a través de un puntero a un archivo Python de un archivo de texto en el modo de sólo lectura utilizando file.readline () en busca de una línea especial. Una vez que encuentro esa línea quiero pasar el puntero del archivo a un método que se espera que el puntero de archivo a estar en el inicio de ese readline (no justo después de ella.)
¿Cómo puedo deshacer esencialmente una file.readline () operación en un puntero a un archivo?
Solución
Hay que recordar la posición llamando file.tell()
antes de la readline y luego llamar a file.seek()
rebobinado. Algo así 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 para llamar dentro de un bucle file.seek()
for line in file
así que por lo general sólo escribir el bucle while
. Probablemente hay una manera mucho más Pythonic de hacer esto.
Otros consejos
grabar el punto de partida de la línea con thefile.tell()
antes de llamar readline
, y volver 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 se ve, la búsqueda / Tell "par" es "deshacer", por así decirlo, el movimiento del puntero del archivo realizado por readline
. Por supuesto, esto sólo puede trabajar en un archivo real reubicable (es decir, el disco), no (por ejemplo) en archivo-como objetos construidos w / el método makefile de tomas de corriente, etc, etc.
Si su método simplemente quiere iterar a través del archivo, entonces se podría utilizar para hacer itertools.chain
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 usted no sabe la última línea debido a que no lo visita se 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