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 denext()
con otros métodos de archivo (comoreadline()
) no funciona bien. Sin embargo, usarseek()
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).