この方法でファイルを反復処理するときに、その理由を誰かが知っていますか?
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()に適切なインデックスを取得します。
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ところで実行しています。
開いているファイルをイテレーターとして使用すると、先読みバッファーを使用して効率が向上します。その結果、行をループすると、ファイルポインタがファイル全体に大きなステップで進みます。
ファイルオブジェクト ドキュメントから:
Forループをファイルの行をループする最も効率的な方法(非常に一般的な操作)にするために、
next()
メソッドは非表示の先読みバッファーを使用します。先読みバッファを使用した結果、next()
を他のファイルメソッド(readline()
など)と組み合わせても正しく機能しません。ただし、seek()
を使用してファイルを絶対位置に再配置すると、先読みバッファーがフラッシュされます。
.tell()
に依存する必要がある場合は、ファイルオブジェクトをイテレータとして使用しないでください。代わりに、.readline()
をイテレータに変えることができます(パフォーマンスがいくらか低下します)。
_for line in iter(f.readline, ''):
print f.tell()
_
これは iter()
functionsentinel
引数を使用して、呼び出し可能オブジェクトをイテレーターに変換します。
答えは、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()
がそのように動作する理由を説明しています。
ドキュメント 提案 パフォーマンス上の理由で作成されています(また、先読みバッファーの特定のサイズを保証するものではありません)。
同じ先読みバッファの問題が発生し、 Martijnの提案 を使用して解決しました。
それ以来、私はそのようなことをしようとしている他の人のために私の解決策を一般化しました:
https://github.com/loisaidasam/csv-position-reader
ハッピーCSV解析!