tempfile – 一時的なファイルシステムリソースを作成する¶
目的: | 一時的なファイルシステムリソースを作成する |
---|---|
利用できるバージョン: | 1.4 以上、2.3 で主要なセキュリティ修正が施された |
多くのプログラムで中間データを書き出すためにファイルを作成する必要性に迫られます。アプリケーションを壊したい攻撃者に推測されないように、セキュアでユニークな名前のファイルを作成することはプログラマの手腕を問われるところです。 tempfile モジュールはセキュアなファイルシステムリソースを作成するための機能を提供します。 TemporaryFile() は無名ファイルをオープンして返します。 NamedTemporaryFile() は名前のあるファイルをオープンして返します。 mkdtemp() は一時的なディレクトリを作成してその名前を返します。
TemporaryFile¶
あるアプリケーションがデータを保存するために一時的なファイルが必要な場合でも、その一時ファイルを他のプログラムと共有する必要はありません。一時ファイルを作成するために最適な選択は TemporaryFile() 関数です。その関数はプラットホーム上にファイルを作成して即座にアンリンクします。ファイルシステムテーブルにそのファイルへの参照先がないため、他のプログラムがそのファイルをオープンしたり見つけたりすることは不可能です。 TemporaryFile() が作成したファイルは、そのファイルを閉じるときに自動的に削除されます。
import os
import tempfile
print 'Building a file name yourself:'
filename = '/tmp/guess_my_name.%s.txt' % os.getpid()
temp = open(filename, 'w+b')
try:
print 'temp:', temp
print 'temp.name:', temp.name
finally:
temp.close()
# 自分で一時ファイルを削除する
os.remove(filename)
print
print 'TemporaryFile:'
temp = tempfile.TemporaryFile()
try:
print 'temp:', temp
print 'temp.name:', temp.name
finally:
# 自動的に一時ファイルを削除する
temp.close()
この例は名前生成に一般的パターンを使用するのと TemporaryFile() 関数を使用するのを比較して、一時ファイルを作成することの違いを表しています。 TemporaryFile() が返すファイルには名前がないことに注目してください。
$ python tempfile_TemporaryFile.py
Building a file name yourself:
temp: <open file '/tmp/guess_my_name.72105.txt', mode 'w+b' at 0x100458270>
temp.name: /tmp/guess_my_name.72105.txt
TemporaryFile:
temp: <open file '<fdopen>', mode 'w+b' at 0x100458780>
temp.name: <fdopen>
デフォルトで一時ファイルは 'w+b' モードで作成されます。そのため、全てのプラットホーム上で一貫して動作して、その一時ファイルに読み書きすることができます。
import os
import tempfile
temp = tempfile.TemporaryFile()
try:
temp.write('Some data')
temp.seek(0)
print temp.read()
finally:
temp.close()
書き込み後、その一時ファイルからデータを読み込むために seek() を使用してファイル位置を巻き戻す必要があります。
$ python tempfile_TemporaryFile_binary.py
Some data
もしその一時ファイルをテキストモードで動作させたいなら、作成するときに 'w+t' モードをセットしてください。
import tempfile
f = tempfile.TemporaryFile(mode='w+t')
try:
f.writelines(['first\n', 'second\n'])
f.seek(0)
for line in f:
print line.rstrip()
finally:
f.close()
その一時ファイルはテキストとしてデータを取り扱います。
$ python tempfile_TemporaryFile_text.py
first
second
NamedTemporaryFile¶
しかし、名前のある一時的なファイルが重要になる状況もあります。アプリケーションが複数のプロセスやホストにまで及ぶなら、名前のある一時ファイルはアプリケーション間でそのデータをやり取りする最も簡単な方法です。 NamedTemporaryFile() 関数は、名前属性からアクセスされる名前のある一時ファイルを作成します。
import os
import tempfile
temp = tempfile.NamedTemporaryFile()
try:
print 'temp:', temp
print 'temp.name:', temp.name
finally:
# 自動的にファイルを削除する
temp.close()
print 'Exists after close:', os.path.exists(temp.name)
その一時ファイルに名前が付けられていても、その一時ファイルが閉じられると削除されます。
$ python tempfile_NamedTemporaryFile.py
temp: <open file '<fdopen>', mode 'w+b' at 0x100458270>
temp.name: /var/folders/5q/8gk0wq888xlggz008k8dr7180000hg/T/tmpcaEzYl
Exists after close: False
mkdtemp¶
複数の一時ファイルを必要とするなら、1つの一時ディレクトリを作成して、その一時ディレクトリ配下で全ファイルをオープンする方がもっと便利でしょう。一時ディレクトリを作成するために mkdtemp() を使用してください。
import os
import tempfile
directory_name = tempfile.mkdtemp()
print directory_name
# Clean up the directory yourself
os.removedirs(directory_name)
ディレクトリはそれ自身が “オープンされたモノ” ではないので使用後に自分でその一時ディレクトリを削除しなければなりません。
$ python tempfile_mkdtemp.py
/var/folders/5q/8gk0wq888xlggz008k8dr7180000hg/T/tmp7DqLan
名前を予測する¶
デバッグ目的のために一時ファイルの名前を予測し易いようにしておくことは役に立ちます。名前のない一時ファイルよりも明らかにセキュアではないですが、名前に予測し易い文字列を含めることはプログラムがその一時ファイルを使用しているときに調査のためにファイルを見つけ易くします。全ての関数は、今のところ、ある程度はファイル名を扱えるように3つの引数を取ります。名前は定型的に生成されます。
dir + prefix + random + suffix
random を除いた全ての値、つまり dir , prefix , suffix が TemporaryFile() , NamedTemporaryFile() や mkdtemp() への引数として渡されます。例えば、
import tempfile
temp = tempfile.NamedTemporaryFile(suffix='_suffix',
prefix='prefix_',
dir='/tmp',
)
try:
print 'temp:', temp
print 'temp.name:', temp.name
finally:
temp.close()
prefix と suffix の引数は、ファイル名生成のためにランダム文字列と組み合わせられます。そして、 dir 引数はそのままで新しいファイルの置き場所として使用されます。
$ python tempfile_NamedTemporaryFile_args.py
temp: <open file '<fdopen>', mode 'w+b' at 0x100458270>
temp.name: /tmp/prefix_og9KcZ_suffix
一時ファイルの場所¶
dir 引数へ明示的に場所を指定しないなら、その一時ファイルが置かれる実際のパスはプラットホームや設定次第で変わります。 tempfile モジュールには実行時に使用される設定を問い合わせる関数が2つあります。
import tempfile
print 'gettempdir():', tempfile.gettempdir()
print 'gettempprefix():', tempfile.gettempprefix()
gettempdir() は全ての一時ファイルに適用するデフォルトディレクトリを返します。 gettempprefix() は新しいファイルとディレクトリ名のための接頭辞を返します。
$ python tempfile_settings.py
gettempdir(): /var/folders/5q/8gk0wq888xlggz008k8dr7180000hg/T
gettempprefix(): tmp
gettempdir() が返す値は現在のプロセスがファイルを作成できるディレクトリリストの最初の場所を調べる線形アルゴリズムに基づいてセットされます。ライブラリドキュメントから引用します。
Python は標準のディレクトリリストを探して、ユーザがファイルを作成できる最初の場所を tempdir にセットします。そのディレクトリリストは次になります。
一時ディレクトリは TMPDIR 環境変数の名前になります。
一時ディレクトリは TEMP 環境変数の名前になります。
一時ディレクトリは TMP 環境変数の名前になります。
プラットホーム固有の場所:
- RiscOS では一時ディレクトリは Wimp$ScrapDir 環境変数の名前になります。
- Windows では一時ディレクトリは C:\TEMP , C:\TMP , \TEMP と \TMP の順番になります。
- その他の全プラットホームでは一時ディレクトリは /tmp , /var/tmp と /usr/tmp の順番になります。
最後の手段としてカレントディレクトリになります。
プログラムが全ての一時ファイルにこれらの環境変数をセットせずにグローバルな場所を明示的に必要とするなら、 tempfile.tempdir を直接的にセットすることができます。
import tempfile
tempfile.tempdir = '/I/changed/this/path'
print 'gettempdir():', tempfile.gettempdir()
$ python tempfile_tempdir.py
gettempdir(): /I/changed/this/path