Est-ce que quelqu'un sait pourquoi, lorsque vous parcourez un fichier de cette façon:
f = open('test.txt', 'r')
for line in f:
print "f.tell(): ",f.tell()
f.tell(): 8192
f.tell(): 8192
f.tell(): 8192
f.tell(): 8192
J'obtiens systématiquement le mauvais index de fichier de tell (). Cependant, si j'utilise readline, j'obtiens l'index approprié pour tell ():
f = open('test.txt', 'r')
while True:
line = f.readline()
if (line == ''):
break
print "f.tell(): ",f.tell()
f.tell(): 103
f.tell(): 107
f.tell(): 115
f.tell(): 124
J'exécute python 2.7.1 BTW.
L'utilisation de fichiers ouverts en tant qu'itérateur utilise un tampon de lecture anticipée pour améliorer l'efficacité. Par conséquent, le pointeur de fichier avance par étapes importantes au fur et à mesure que vous parcourez les lignes.
Depuis le Objets du fichier documentation:
Afin de faire de la boucle for le moyen le plus efficace de boucler sur les lignes d'un fichier (opération très courante), la méthode
next()
utilise un tampon de lecture anticipée masqué. L'utilisation d'un tampon de lecture anticipée a pour conséquence que la combinaison denext()
avec d'autres méthodes de fichier (commereadline()
) ne fonctionne pas correctement. Cependant, utiliserseek()
pour repositionner le fichier sur une position absolue videra le tampon de lecture anticipée.
Si vous devez vous fier à .tell()
, n'utilisez pas l'objet fichier en tant qu'itérateur. Vous pouvez plutôt transformer .readline()
en itérateur (au prix d'une perte de performance):
for line in iter(f.readline, ''):
print f.tell()
Ceci utilise l'argument iter()
functionsentinel
pour transformer tout appelable en itérateur.
La réponse se trouve dans la partie suivante du code source 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;
}
Comme vous pouvez le constater, l’interface itérateur de file
lit le fichier par blocs de 8 Ko. Ceci explique pourquoi f.tell()
se comporte comme il le fait.
La documentation suggère c'est fait pour des raisons de performances (et ne garantit pas une taille particulière du tampon readahead).
J'ai rencontré le même problème de tampon de lecture anticipée et l'ai résolu à l'aide de suggestion de Martijn .
Depuis, j'ai généralisé ma solution à quiconque cherche à faire de telles choses:
https://github.com/loisaidasam/csv-position-reader
Bonne analyse CSV!