fichier.tell() la contradiction
Quelqu'un arrive à savoir pourquoi lorsque vous parcourez un fichier de cette façon:
Entrée:
f = open('test.txt', 'r')
for line in f:
print "f.tell(): ",f.tell()
Sortie:
f.tell(): 8192
f.tell(): 8192
f.tell(): 8192
f.tell(): 8192
J'obtiens toujours le mauvais index de fichier de tell (), cependant, si j'utilise readline, j'obtiens l'index approprié pour tell ():
Entrée:
f = open('test.txt', 'r')
while True:
line = f.readline()
if (line == ''):
break
print "f.tell(): ",f.tell()
Sortie:
f.tell(): 103
f.tell(): 107
f.tell(): 115
f.tell(): 124
Je cours Python 2.7.1 BTW.
3 réponses
L'utilisation de fichiers ouverts en tant qu'itérateur utilise un tampon de lecture anticipée pour augmenter l'efficacité. Par conséquent, le pointeur de fichier avance en grandes étapes à travers le fichier que vous faites une boucle sur les lignes.
À partir des objets du fichier documentation:
Afin de faire d'une boucle for le moyen le plus efficace de boucler les lignes d'un fichier (une opération très courante), la méthode
next()
utilise un tampon de lecture anticipée caché. En conséquence de l'utilisation d'un tampon de lecture anticipée, la combinaison denext()
avec d'autres méthodes de fichiers (commereadline()
) ne fonctionne pas correctement. Cependant, l'utilisation deseek()
pour repositionner le fichier en position absolue videra le tampon de lecture anticipée.
Si vous devez vous appuyer sur .tell()
, n'utilisez pas l'objet file comme itérateur. Vous pouvez transformer .readline()
en un itérateur à la place (au prix d'une perte de performance):
for line in iter(f.readline, ''):
print f.tell()
Cela utilise le iter()
Fonction sentinel
argument pour transformer tout appelable en un itérateur.
La réponse réside dans la partie suivante du code source 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;
}
Comme vous pouvez le voir, l'interface itérateur de file
lit le fichier en blocs de 8 Ko. Cela explique pourquoi f.tell()
se comporte comme il le fait.
La documentation suggère c'est fait pour des raisons de performance (et ne garantit aucune taille particulière du tampon readahead).
J'ai rencontré le même problème de tampon de lecture anticipée et je l'ai résolu en utilisant la suggestion de Martijn .
J'ai depuis généralisé ma solution pour tous ceux qui cherchent à faire de telles choses:
Https://github.com/loisaidasam/csv-position-reader
Bonne analyse CSV!