Python一時ファイルにデータを書き込む必要があるスクリプトを作成し、一時ファイルを読み取るC++プログラムを実行するサブプロセスを作成します。使用しようとしています- NamedTemporaryFile
これには、ドキュメントによると、
名前を使用してファイルを再度開くことができるかどうか、名前付き一時ファイルがまだ開いている間は、プラットフォームによって異なります(UNIXでは使用できますが、Windows NT以降では使用できません)。
そして実際、Windowsで書き込み後に一時ファイルをフラッシュしても、それが消えるまで閉じない場合、サブプロセスは読み取りのためにそれを開くことができません。
これを回避するには、delete=False
を使用してファイルを作成し、サブプロセスを生成する前にファイルを閉じ、完了したら手動で削除します。
fileTemp = tempfile.NamedTemporaryFile(delete = False)
try:
fileTemp.write(someStuff)
fileTemp.close()
# ...run the subprocess and wait for it to complete...
finally:
os.remove(fileTemp.name)
これはエレガントではないようです。これを行うためのより良い方法はありますか?おそらく、サブプロセスがそれを取得できるように一時ファイルのアクセス許可を開く方法ですか?
少なくとも、既存のPythonライブラリを使用して一時ファイルを開く場合、Windowsの場合、複数のプロセスからのアクセスは不可能です。 [〜#〜] msdn [〜# 〜] 3番目のパラメーター(dwSharedMode
)共有モードフラグ_FILE_SHARE_READ
_をCreateFile()
関数に指定できます。
ファイルまたはデバイスでの後続のオープン操作を有効にして、読み取りアクセスを要求します。そうしないと、他のプロセスが読み取りアクセスを要求した場合、ファイルまたはデバイスを開くことができません。このフラグが指定されていないが、ファイルまたはデバイスが読み取りアクセス用に開かれている場合、関数は失敗します。
したがって、カスタムの一時ファイルオープナー関数を作成するWindows固有のCルーチンを記述し、Pythonから呼び出すと、サブプロセスがエラーなしでファイルにアクセスできるようになります。最もポータブルなバージョンであり、どのシステムでも動作するため、最もエレガントな実装であるため、既存のアプローチに固執する必要があると思います。
編集:Windowsの複数のプロセスから一時ファイルを開いて読むことも可能です。 Piotr Dobrogostの answer を参照してください。
誰もこの情報を公開することに興味がないようです...
tempfile
は関数mkdtemp()
を公開しますが、これはこの問題を単純化できます。
_try:
temp_dir = mkdtemp()
temp_file = make_a_file_in_a_dir(temp_dir)
do_your_subprocess_stuff(temp_file)
remove_your_temp_file(temp_file)
finally:
os.rmdir(temp_dir)
_
mkstemp()
を使用して一時ファイル自体のセキュリティを強化したり、削除する前にインプレースでファイルを上書きしたりすることができるため、中間関数の実装はリーダーに任せます。 。 tempfile
のソースを熟読することで簡単に計画できないセキュリティ制限があるかどうかは特にわかりません。
とにかく、はい、WindowsでNamedTemporaryFile
を使用するのは洗練されていないかもしれません。ここでの私のソリューションも洗練されていないかもしれませんが、エレガントなコードよりもWindowsのサポートが重要であると既に決めているので、先に進んで読みやすい何かをします。
According Richard Oudkerkに
(...)Windowsで
NamedTemporaryFile
を再オープンしようとすると失敗する唯一の理由は、再オープンするときに_O_TEMPORARY
_を使用する必要があるためです。
彼はこれを行う方法の例をPython 3.3+
_import os, tempfile
DATA = b"hello bob"
def temp_opener(name, flag, mode=0o777):
return os.open(name, flag | os.O_TEMPORARY, mode)
with tempfile.NamedTemporaryFile() as f:
f.write(DATA)
f.flush()
with open(f.name, "rb", opener=temp_opener) as f:
assert f.read() == DATA
assert not os.path.exists(f.name)
_
ビルトインopen()
in Python 2.x)にはopener
パラメーターがないため、下位レベルos.open()
を結合する必要があります同じ効果を達成するos.fdopen()
関数:
_import subprocess
import tempfile
DATA = b"hello bob"
with tempfile.NamedTemporaryFile() as f:
f.write(DATA)
f.flush()
subprocess_code = \
"""import os
f = os.fdopen(os.open(r'{FILENAME}', os.O_RDWR | os.O_BINARY | os.O_TEMPORARY), 'rb')
assert f.read() == b'{DATA}'
""".replace('\n', ';').format(FILENAME=f.name, DATA=DATA)
subprocess.check_output(['python', '-c', subprocess_code]) == DATA
_
あなたはいつでも低レベルに行くことができますが、あなたにとって十分にきれいかどうかはわかりません:
fd, filename = tempfile.mkstemp()
try:
os.write(fd, someStuff)
os.close(fd)
# ...run the subprocess and wait for it to complete...
finally:
os.remove(filename)