2010-08-17 12 views
23

Estoy navegando por 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 justo después)Python: Deshacer una operación readline() del archivo Python para que el puntero del archivo vuelva al estado original

¿Cómo puedo deshacer un archivo file.readline () operación en un puntero de archivo?

Respuesta

35

Debe recordar la posición llamando al file.tell() antes de la línea de lectura y luego llamando al file.seek() para rebobinar. 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 file.seek() dentro de un bucle for line in file así que por lo general sólo escribir el bucle while. Probablemente hay una manera mucho más pitonica de hacer esto.

+1

no parece ser seguro que llamar a un bucle de línea en el archivo. "OSError: indicando la posición deshabilitada por la próxima() llamada" – Jiminion

11

Registra el punto de inicio de la línea con thefile.tell() antes de llamar al readline, y regrese 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, el "par" 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 actual buscable (es decir, disco), no (por ejemplo) en objetos similares a archivos construidos con el método makefile de sockets, etc. etc.

3

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 
+0

Solución agradable y limpia. –

+0

Excepto que no se mueve hacia atrás ... –

1
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 
+0

Estoy pensando en la misma línea que usted, pero la ayuda de file.seek sugiere lo contrario: 'Si el archivo se abre en modo texto, solo las compensaciones devueltas por tell() son legal. –

+0

Lo he usado algunas veces y no he tenido ningún problema, supongo que tiene algo que ver con otras codificaciones de caracteres – GWW

+0

en modo texto, '\ r \ n' se va a traducir a '\ n' así que perderás un personaje. En este caso, ese carácter sería el CR ('\ r') para que nadie lo note;) –

Cuestiones relacionadas