2010-10-11 20 views
56

Para un ejercicio que estoy haciendo, intento leer el contenido de un archivo determinado dos veces usando el método read(). Extrañamente, cuando lo llamo por segunda vez, ¿no parece devolver el contenido del archivo como una cadena?¿Por qué no puedo llamar a read() dos veces en un archivo abierto?

Aquí está el código

f = f.open() 

# get the year 
match = re.search(r'Popularity in (\d+)', f.read()) 

if match: 
    print match.group(1) 

# get all the names 
matches = re.findall(r'<td>(\d+)</td><td>(\w+)</td><td>(\w+)</td>', f.read()) 

if matches: 
    # matches is always None 

Por supuesto que sé que este no es el más eficiente o mejor manera, este no es el punto aquí. El punto es, ¿por qué no puedo llamar al read() dos veces? ¿Tengo que restablecer el manejador del archivo? ¿O cerrar/volver a abrir el archivo para hacer eso?

+2

¿De dónde sacaste la idea de que leer no cambiaría el estado del archivo? ¿Qué referencia o tutorial estás usando? –

+0

Creo que cerrar y volver a abrir el archivo debería funcionar en función de los valores a continuación. – Anthony

+0

@Shynthriir: Cerrar y volver a abrir el archivo no siempre es una buena idea ya que puede tener otros efectos en el sistema (archivos temporales, incron, etc.). –

Respuesta

88

Llamando read() lee todo el archivo y deja el cursor de lectura al final del archivo (sin nada más que leer). Si está buscando leer una cierta cantidad de líneas a la vez, puede usar readline(), readlines() o recorrer las líneas con for line in handle:.

Para responder a su pregunta directamente, una vez que un archivo ha sido leído, con read() puede utilizar seek(0) para devolver el cursor de lectura al inicio del archivo (docs son here). Si sabe que el archivo no va a ser demasiado grande, también puede guardar el resultado read() en una variable, utilizándolo en sus expresiones completas.

Ps. No olvide cerrar el archivo después de que haya terminado;

+3

+1, Sí, lea la variable temporal para evitar archivos innecesarios de E/S. Es una economía falsa que está guardando cualquier memoria porque tiene menos variables (explícitas). –

+2

@NickT: supongo que un archivo pequeño que se lee varias veces se almacena en caché por el sistema operativo (al menos en Linux/OSX), por lo que no hay archivos adicionales de E/S para leer dos veces. Los archivos grandes que no caben en la memoria no se almacenan en caché, pero no desea leerlos en una variable porque comenzará a intercambiarse. Entonces, en caso de duda, siempre lea varias veces. Si está seguro de que los archivos son pequeños, haga lo que le dé el mejor programa. – Claude

+0

El desmontaje se puede automatizar con ['with'] (http://effbot.org/zone/python-with-statement.htm). –

13

El puntero de lectura se mueve después del último byte/carácter leído. Use el método seek() para rebobinar el puntero de lectura al principio.

2

Cada archivo abierto tiene una posición asociada.
Cuando lee() lee de esa posición. Por ejemplo read(10) lee los primeros 10 bytes de un archivo recién abierto, luego otro read(10) lee los siguientes 10 bytes. read() sin argumentos lee todos los contenidos del archivo, dejando la posición del archivo al final del archivo. La próxima vez que llame al read() no hay nada que leer.

Puede usar seek para mover la posición del archivo. O probablemente sea mejor en su caso hacer un read() y mantener el resultado para ambas búsquedas.

13

Todos los que han respondido esta pregunta hasta ahora están en lo cierto: read() se mueve a través del archivo, por lo que después de haberlo llamado, no puede volver a llamarlo.

Lo que voy a agregar es que en su caso particular, no necesita volver al inicio o volver a abrir el archivo, puede simplemente almacenar el texto que ha leído en una variable local, y usar dos veces, o tantas veces como se quiera, en su programa:

f = f.open() 
text = f.read() # read the file into a local variable 
# get the year 
match = re.search(r'Popularity in (\d+)', text) 
if match: 
    print match.group(1) 
# get all the names 
matches = re.findall(r'<td>(\d+)</td><td>(\w+)</td><td>(\w+)</td>', text) 
if matches: 
    # matches will now not always be None 
+1

+1 En realidad, esta fue la solución propuesta para este ejercicio (http://code.google.com/intl/de-DE/edu/languages/google-python-class/exercises/baby-names.html). Pero de alguna manera no pensé en almacenar la cadena en una variable. D'oh! – helpermethod

+1

Con Python3, use pathlib. 'from pathlib import Ruta; text = Path (filename) .read_text() 'Se encarga de abrir, cerrar, etc. – PaulMcG

1

read() consume. Por lo tanto, puede reiniciar el archivo, o buscar al inicio antes de volver a leer. O bien, si satisface su tarea, puede usar read(n) para consumir solo n bytes.

12

sí, como arriba ...

voy a escribir sólo un ejemplo:

>>> a = open('file.txt') 
>>> a.read() 
#output 
>>> a.seek(0) 
>>> a.read() 
#same output 
1

siempre encuentro el método de lectura algo así como un paseo por un callejón oscuro. Bajas un poco y te detienes, pero si no cuentas tus pasos, no estás seguro de lo avanzado que estás. Seek da la solución reposicionando, la otra opción es Tell que devuelve la posición a lo largo del archivo. Puede ser el archivo de Python api puede combinar leer y buscar en un read_from (posición, bytes) para hacerlo más simple, hasta que eso suceda, debe leer this page.

Cuestiones relacionadas