file.tell()不一致
有人碰巧知道为什么当你这样迭代一个文件:
input:
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
我始终从tell()获取错误的文件索引,但是,如果使用readline,我将得到tell()的适当索引:
input:
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
我正在运行Python 2.7.1顺便说一句。
使用打开文件作为迭代器使用预读缓冲区来提高效率。 因此,在循环遍历文件时,文件指针在整个文件中大步前进。
从File Objects文档:
为了使循环成为循环遍历文件行的最有效方式(一个非常常见的操作),
next()
方法使用一个隐藏的预读缓冲区。 作为使用预读缓冲区的结果,将next()
与其他文件方法(如readline()
)结合使用是行不通的。 但是,使用seek()
将文件重新定位到绝对位置将刷新预读缓冲区。
如果您需要依赖.tell()
,请不要将该文件对象用作迭代器。 您可以将.readline()
转换为一个迭代器(代价是性能下降):
for line in iter(f.readline, ''): print f.tell()
这使用iter()
函数 sentinel
参数将任何可调用变成一个迭代器。
答案在于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; }
如你所见, file
的迭代器接口以8KB的块读取文件。 这解释了为什么f.tell()
行为方式。
文档表明这是出于性能原因(并不保证readahead缓冲区的任何特定大小)。