2011-11-16 16 views
17

mmapインターフェイスはreadline()しかサポートしていないようです。 オブジェクトを反復しようとすると、完全な行ではなく文字が得られます。Pythonでmmapファイルから行を読み込む方法は?

mmap'edファイルを1行ずつ読み込む「pythonic」方法は何ですか?

import sys 
import mmap 
import os 


if (len(sys.argv) > 1): 
    STAT_FILE=sys.argv[1] 
    print STAT_FILE 
else: 
    print "Need to know <statistics file name path>" 
    sys.exit(1) 


with open(STAT_FILE, "r") as f: 
    map = mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ) 
    for line in map: 
    print line # RETURNS single characters instead of whole line 
+1

である通常のファイルとは反対に、このためのメモリマップファイルを使用する動機は何でしょうか。 – NPE

+1

@aix:GBの生データを持っている可能性があり、可能な限り効率的な方法でアクセスしたいと考えています。しかし、本当の理由は:それはよりクーラーです:) –

+0

私はそれがよりクーラーかどうかわかりませんが、あなたは単にそれがより速いと仮定すべきではありません(あなたが本当に気にしていれば、プロファイルする必要があります)。 – NPE

答えて

22

mmapの行を反復処理するための最も簡潔な方法は、関心のうち

with open(STAT_FILE, "r+b") as f: 
    map = mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ) 
    for line in iter(map.readline, ""): 
     # whatever 
+2

私は 'iter'がこの' callable'/'sentinel'引数を取ったことを知らなかった。 +1して私の答えを削除しました。 –

+0

そして、オープンモードを 'r'の代わりに' r + b'に変更してください(下記の私の記事で説明します)。 – hochl

+0

@hochl:ありがとう、終わった。 –

12

私はこのようなあなたの例を修正:

with open(STAT_FILE, "r+b") as f: 
     m=mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ) 
     while True: 
       line=m.readline() 
       if line == '': break 
       print line.rstrip() 

提案:

  • が、これは組み込み関数で、変数mapを呼び出すことはありません。
  • ファイルr+bmmapヘルプページのPythonの例のように開きます。状態:どちらの場合でも、更新のために開かれたファイルのファイル記述子を提供する必要がありますhttp://docs.python.org/library/mmap.html#mmap.mmapを参照してください。
  • グローバル変数名http://www.python.org/dev/peps/pep-0008に記載されているように、グローバル変数名UPPER_CASE_WITH_UNDERSCORESを使用しない方が良いです。他のプログラミング言語(Cのような)では、多くの場合、定数はすべて大文字で記述されます。

これが役に立ちます。

EDIT:コメントは私に不思議に思ったので、私はLinuxでいくつかのタイミングテストを行った。 137MBのテキストファイルで5回連続して実行されたタイミングを比較します。

# normal file access. 
real 2.410 2.414 2.428 2.478 2.490 
sys  0.052 0.052 0.064 0.080 0.152 
user 2.232 2.276 2.292 2.304 2.320 

# mmap file access. 
real 1.885 1.899 1.925 1.940 1.954 
sys  0.088 0.108 0.108 0.116 0.120 
user 1.696 1.732 1.736 1.744 1.752 

これらのタイミングは(私はそれを除く)print文が含まれていません。これらの数字に続いて、私はメモリマップされたファイルへのアクセスがかなり速いと言うでしょう。

EDIT 2:python -m cProfile test.pyを使用して、私は以下の結果を得た:

5432833 2.273 0.000 2.273 0.000 {method 'readline' of 'file' objects} 
5432833 1.451 0.000 1.451 0.000 {method 'readline' of 'mmap.mmap' objects} 

私は間違っていない場合は、mmapはかなり速いです。

さらに、not len(line)line == ''より悪く実行されているようですが、少なくともプロファイラの出力をどのように解釈するのでしょうか。

+0

'AttributeError: 'mmap.mmap'オブジェクトに属性 'readlines'がありません –

+1

hochl:ありがとうございます。ベンチマークは素晴らしいです。テストを再現し、分析を確認するためのスクリプトを添付できますか? –

+1

私は単純にあなたのプログラムの中でそのプリントをコメントアウトしてから、 'time test.py'を10回した後、5つの中間値を取った。 'python -m cProfile test.py'の結果を確認することは興味深いでしょう。 – hochl

1

次は合理的に簡潔である:

with open(STAT_FILE, "r") as f: 
    m = mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ) 
    while True: 
     line = m.readline() 
     if line == "": break 
     print line 
    m.close() 

lineが改行を保持するので、あなたはそれを削除したいかもしれません。 if line == ""が正しいことをするのも理由です(空の行は"\n"として返されます)。

オリジナルの反復が動作する理由は、mmapがファイルと文字列の両方に見えることです。これは、繰り返しの目的のための文字列のように見えます。

readlines()/xreadlines()を提供できない(または選択しない)理由がわかりません。

+0

ファイルオブジェクトの 'readlines()'メソッドは、ファイルのすべての行のリストを返します。 mmapファイルでこれを行うと、mmapの目的が完全に無効になります。 –

+0

@SvenMarnach:それはジェネレータかもしれません。いずれにせよ、まったく正直であるために、私はこの全体の質問でメモリマップされたファイルの必要性を見逃しています。 – NPE

+0

あなたは完全に正しいです。だから、そのような発電機が存在しない理由は、それが無意味であるということです。 :) –

関連する問題