variable python python-2.7 buffering

variable - buffer python



incoherencia de file.tell() (2)

¿Alguien sabe por qué cuando iteras sobre un archivo de esta manera?

Entrada:

f = open(''test.txt'', ''r'') for line in f: print "f.tell(): ",f.tell()

Salida:

f.tell(): 8192 f.tell(): 8192 f.tell(): 8192 f.tell(): 8192

Constantemente obtengo el índice de archivo incorrecto de tell (), sin embargo, si uso readline obtengo el índice apropiado para tell ():

Entrada:

f = open(''test.txt'', ''r'') while True: line = f.readline() if (line == ''''): break print "f.tell(): ",f.tell()

Salida:

f.tell(): 103 f.tell(): 107 f.tell(): 115 f.tell(): 124

Estoy ejecutando python 2.7.1 BTW.


El uso de archivos abiertos como un iterador utiliza un buffer de lectura anticipada para aumentar la eficiencia. Como resultado, el puntero de archivo avanza en grandes pasos por el archivo a medida que recorre las líneas.

De la documentación de Objetos de archivo :

Para hacer que un bucle for sea la forma más eficiente de recorrer las líneas de un archivo (una operación muy común), el método next() usa un búfer de lectura anticipada oculto. Como consecuencia del uso de un búfer de lectura anticipada, la combinación de next() con otros métodos de archivo (como readline() ) no funciona bien. Sin embargo, usar seek() para reposicionar el archivo a una posición absoluta vaciará el búfer de lectura anticipada.

Si necesita confiar en .tell() , no use el objeto de archivo como un iterador. En su lugar, puede convertir .readline() en un iterador (al precio de alguna pérdida de rendimiento):

for line in iter(f.readline, ''''): print f.tell()

Esto usa el argumento sentinel función iter() para convertir cualquier invocable en un iterador.


La respuesta se encuentra en la siguiente parte del código fuente de Python 2.7 ( fileobject.c ):

#define READAHEAD_BUFSIZE 8192 static PyObject * file_iternext(PyFileObject *f) { PyStringObject* l; if (f->f_fp == NULL) return err_closed(); if (!f->readable) return err_mode("reading"); l = readahead_get_line_skip(f, 0, READAHEAD_BUFSIZE); if (l == NULL || PyString_GET_SIZE(l) == 0) { Py_XDECREF(l); return NULL; } return (PyObject *)l; }

Como puede ver, la interfaz del iterador del archivo lee el archivo en bloques de 8 KB. Esto explica por qué f.tell() comporta de la manera en que lo hace.

La documentación sugiere que se hace por razones de rendimiento (y no garantiza ningún tamaño particular del buffer readahead).