2009-07-12
直接的にコンテンツを読み込む代わりのメモリマップファイル
mmap - Memory-map files instead of reading the contents directly
本稿は上記リンク元の和訳になります
本稿は Creative Commons 表示-非営利-継承 3.0でライセンスされています
転載ミス、誤訳等については適宜修正します
Creative Commons 表示-非営利-継承 3.0 アメリカ合衆国
目的: 直接的にコンテンツを読み込む代わりのメモリマップファイル
Python バージョン: 2.1以上
メモリマップファイルを作成するために mmap() 関数を使ってみましょう。Unix と Windows で、以下のように議論されていない mmap() への引数と振る舞いの違いがあります。詳細については、ライブラリドキュメントを参照してください。
最初の引数 fileno は、ファイルオブジェクトの fileno() メソッドか、又は os.open() のファイルオブジェクトになりますmmap() を呼び出す前にファイルをオープンしたので、あなたはそのクローズに責任を持つ必要があります。
mmap() への2番目の引数は、マップするファイルのバイトサイズになります。もし、値がゼロならば、完全なファイルがマップされます。Windows ではゼロの長さのマッピングを作成することはできません。もし、サイズが現在のファイルサイズよりも大きいならば、ファイルは拡張されます。
オプションのキーワード引数である access は、両方のプラットホームでサポートされています。read-only には ACCESS_READ を、write-through (メモリへの書き込みが直接的にファイルへ書き込まれる)には ACCESS_WRITE を、copy-on-write (ファイルへ書き込まれないメモリへの書き込み)には ACCESS_COPY を使用してください。
ファイルと文字列 API
メモリマップファイルは、必要に応じて、ファイルのようなオブジェクトや変更可能な文字列として扱うことができます。1つのマップファイルは、 close(), flush(), read(), readline(), seek(), tell() と write() のような、期待したファイル API メソッドをサポートします。それはまた、スライシングや find() メソッドのような機能で、文字列 API もサポートします。
サンプルデータ
全ての例は、少しのロレム・イプサムを含む、テキストファイル lorem.txt を使用します。参考までに、そのファイルのテキストは以下になります:
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec egestas, enim et consectetuer ullamcorper, lectus ligula rutrum leo, a elementum elit tortor eu quam. Duis tincidunt nisi ut ante. Nulla facilisi. Sed tristique eros eu libero. Pellentesque vel arcu. Vivamus purus orci, iaculis ac, suscipit sit amet, pulvinar eu, lacus. Praesent placerat tortor sed nisl. Nunc blandit diam egestas dui. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Aliquam viverra fringilla leo. Nulla feugiat augue eleifend nulla. Vivamus mauris. Vivamus sed mauris in nibh placerat egestas. Suspendisse potenti. Mauris massa. Ut eget velit auctor tortor blandit sollicitudin. Suspendisse imperdiet justo.
読み込み
read-only アクセスのためにファイルをマップするには、access=mmap.ACCESS_READ を引数に渡してください:
import mmap f = open('lorem.txt', 'r') try: m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) try: print 'First 10 bytes via read :', m.read(10) print 'First 10 bytes via slice:', m[:10] print '2nd 10 bytes via read :', m.read(10) finally: m.close() finally: f.close()
この例では、ファイルポインタを前に進める read() を呼び出したとしても、ファイルポインタはリセットされたのでスライシング操作は、同じ最初の10バイトを返します。そのファイルポインタは最後のアクセスを追跡していて、2回目のために最初の10バイトを返すスライシング操作を行った後で、そのファイルの次の10バイトを返す read() を呼びます。
$ python mmap_read.py First 10 bytes via read : Lorem ipsu First 10 bytes via slice: Lorem ipsu 2nd 10 bytes via read : m dolor si
書き込み
メモリマップファイルへ書き込む必要がある場合、それをマッピングする前に読み書きモード(‘w’ ではなく ‘r+’)でそれをオープンしてください。それから、データを変更する API メソッド(write() やスライスへの書き込み等)を使用してください。
ここに ACCESS_WRITE のデフォルトアクセスモードを使用して、ある行の一部を変更するスライスへ書き込みをする例があります。:
import mmap import shutil # サンプルファイルをコピー shutil.copyfile('lorem.txt', 'lorem_copy.txt') word = 'consectetuer' reversed = word[::-1] print 'Looking for :', word print 'Replacing with :', reversed f = open('lorem_copy.txt', 'r+') try: m = mmap.mmap(f.fileno(), 0) try: print 'Before:', m.readline().rstrip() m.seek(0) # rewind loc = m.find(word) m[loc:loc+len(word)] = reversed m.flush() m.seek(0) # rewind print 'After :', m.readline().rstrip() finally: m.close() finally: f.close()
ご覧の通り、最初の行の中間にある単語は置換されました。
$ python mmap_write_slice.py Looking for : consectetuer Replacing with : reutetcesnoc Before: Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec After : Lorem ipsum dolor sit amet, reutetcesnoc adipiscing elit. Donec
ACCESS_COPY モード
ディスク上のファイルに変更を書き込まないようにするには ACCESS_COPY モードを使用してください。
import mmap import shutil # サンプルファイルをコピー shutil.copyfile('lorem.txt', 'lorem_copy.txt') word = 'consectetuer' reversed = word[::-1] f = open('lorem_copy.txt', 'r+') try: m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_COPY) try: print 'Memory Before:', m.readline().rstrip() print 'File Before :', f.readline().rstrip() print m.seek(0) # rewind loc = m.find(word) m[loc:loc+len(word)] = reversed m.seek(0) # rewind print 'Memory After :', m.readline().rstrip() f.seek(0) print 'File After :', f.readline().rstrip() finally: m.close() finally: f.close()
この例では、mmap ファイルハンドラとは別にファイルハンドラを巻き戻す必要があったのに注意してください。
$ python mmap_write_copy.py Memory Before: Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec File Before : Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec Memory After : Lorem ipsum dolor sit amet, reutetcesnoc adipiscing elit. Donec File After : Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec
正規表現
メモリマップファイルは文字列のように動作するので、正規表現のような、文字列の操作をする他のモジュールと一緒に使用することができます。この例は “nulla” を含む全ての文を見つけます。
import mmap import re pattern = re.compile(r'(\.\W+)?([^.]?nulla[^.]*?\.)', re.DOTALL | re.IGNORECASE | re.MULTILINE) f = open('lorem.txt', 'r') try: m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) try: for match in pattern.findall(m): print match[1].replace('\n', ' ') finally: m.close() finally: f.close()
2つのグループを含むパターンなので、findall() からの戻り値はタプルのシーケンスになります。print 文は、改行をスペースに置換した match の文を取り出して、その結果は1行で表示されます。
$ python mmap_regex.py Nulla facilisi. Nulla feugiat augue eleifend nulla.
関連項目
mmap mmap の標準ライブラリドキュメント os(未訳) os モジュール
- 24 http://www.google.co.jp/search?hl=ja&client=firefox-a&rls=org.mozilla:ja-JP-mac:official&hs=mqz&q=centos+unzip+日本語+文字化け&btnG=検索&lr=lang_ja
- 19 http://www.google.co.jp/search?sourceid=navclient&hl=ja&ie=UTF-8&rlz=1T4GGLL_ja&q=python+split
- 9 http://twitter.com/t2y
- 8 http://atnd.org/events/1062
- 7 http://www.google.com/search?hl=ja&lr=lang_ja&ie=UTF-8&oe=UTF-8&q=Zabbix+1.6&num=50
- 6 http://reader.livedoor.com/reader/
- 5 http://www.google.co.jp/search?hl=ja&lr=lang_ja&client=firefox-a&rls=org.mozilla:ja:official&hs=6EG&ei=eeBaSqveMtSIkQXB6IjUBQ&sa=X&oi=spell&resnum=1&ct=result&cd=1&q=base64+padding&spell=1
- 4 http://ezsch.ezweb.ne.jp/search/?sr=0101&query=恵比寿 ボエム
- 4 http://search.yahoo.co.jp/search?p=c言語+パスワード+入力&ei=UTF-8&fr=top_ga1_sa&x=wrt
- 4 http://www.google.co.jp/search?client=firefox-a&rls=org.mozilla:ja-JP-mac:official&channel=s&hl=ja&q=ネストされた値 json変換&lr=&btnG=Google+検索
