Python で UTF-8 でエンコードされたドキュメントをシークおよびテルで操作できますか?
質問
500MBを超える大きなログファイルを生成するアプリケーションがあります。
ログ ファイルをすばやく参照して目的のデータを見つけることができるユーティリティを Python でいくつか作成しました。しかし、ファイルが大きすぎてすべてをメモリに読み込むことができないデータセットをいくつか取得しました。
したがって、ドキュメントを一度スキャンしてインデックスを作成し、一度に参照したいドキュメントのセクションのみをメモリにロードしたいと考えています。
これは、「ファイル」を開いて一度に1行ずつ読み取り、file.tell()からオフセットを保存するときに機能します。その後、 file.seek( offset, 0 ) を使用して、ファイルのそのセクションに戻ることができます。
ただし、私の問題は、ログファイルにUTF-8が含まれている可能性があるため、コーデックモジュールで開く必要があることです(codecs.open(<filename>, 'r', 'utf-8')
)。結果のオブジェクトを使用して、seek と Tell を呼び出すことができますが、それらは一致しません。
コーデックは何らかのバッファリングを行う必要があると思いますか、それともテルからバイト数ではなく文字数を返すのでしょうか?
これを回避する方法はありますか?
解決
true の場合、バイトと文字のオフセットが混乱している可能性があるため、これはコーデック モジュールのバグまたは制限のように思えます。
私は通常のものを使用します open()
ファイルを開く関数、その後 seek()
/tell()
常に一貫したバイト オフセットが得られます。読みたいときにいつでもご利用ください f.readline().decode('utf-8')
.
ただし、 f.read()
関数を使用すると、マルチバイト文字の途中に到達して、UTF-8 デコード エラーが発生する可能性があります。 readline()
常に機能します。
これはバイト オーダー マークを透過的に処理しませんが、いずれにしてもログ ファイルに BOM がない可能性があります。
他のヒント
UTF-8 の場合、実際には codecs.open でファイルを開く必要はありません。代わりに、最初にファイルをバイト文字列として読み取り、その後でのみ個々のセクションをデコードする (文字列に対して .decode メソッドを呼び出す) 方が確実です。行境界でファイルを分割しても安全です。分割する唯一の安全でない方法は、マルチバイト文字の途中で分割することです (バイト値 > 128 から認識できます)。
Python の UTF8 で行われていることの多くは、それが Python 3 でどのように行われたかを考えれば理解できます。あなたの場合、『Dive into Python 3』の「ファイル」の章を読むと、より理解できるでしょう。 http://diveintopython3.org/files.html
ただし、短いのは、 file.seek
そして file.tell
Unicode 文字は複数のバイトを占める可能性があるのに対し、Unicode 文字はバイト位置を扱います。したがって、次のようにすると:
f.seek(10)
f.read(1)
f.tell()
それ以外のものは簡単に手に入る 17
, 読み取った 1 文字の長さによって異なります。
アップデート:codec.open() によって返されたオブジェクトに対してシーク/テルを行うことはできません。通常のファイルを使用し、読み取り後に文字列を Unicode にデコードする必要があります。
なぜ機能しないのかはわかりませんが、機能させることはできません。たとえば、シークは 1 回しか機能しないように見えます。その後、ファイルを閉じて再度開く必要がありますが、もちろんこれは役に立ちません。
このテルでは文字の位置は使用されませんが、ストリーム内の位置は表示されません (ただし、おそらく、ディスクからの読み取り時に基礎となるファイル オブジェクトがどこにあるかは表示されます)。
したがって、おそらく何らかの基礎的なバッファリングが原因で、それを実行することはできません。ただし、読み取り後の復号化は問題なく機能するため、そのまま実行してください。