[英]How to create a temporary file that can be read by a subprocess?
我正在編寫一個 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)
這似乎不優雅。 有一個更好的方法嗎? 也許是一種打開臨時文件權限的方法,以便子進程可以訪問它?
由於似乎沒有其他人有興趣公開這些信息......
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 支持比優雅的代碼更重要,所以您不妨繼續做一些可讀的事情。
根據理查德 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)
因為 Python 2.x 中內置的open()
中沒有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)
至少如果您使用現有的 Python 庫打開一個臨時文件,則在 Windows 的情況下無法從多個進程訪問它。 根據MSDN ,您可以為CreateFile()
函數指定第三個參數( dwSharedMode
)共享模式標志FILE_SHARE_READ
:
啟用對文件或設備的后續打開操作以請求讀取訪問權限。 否則,如果其他進程請求讀取訪問權限,它們將無法打開文件或設備。 如果未指定此標志,但已打開文件或設備以進行讀取訪問,則函數失敗。
因此,您可以編寫一個 Windows 特定的 C 例程來創建一個自定義的臨時文件打開器函數,從 Python 調用它,然后您可以讓您的子進程訪問該文件而不會出現任何錯誤。 但我認為你應該堅持你現有的方法,因為它是最便攜的版本,可以在任何系統上工作,因此是最優雅的實現。
編輯:原來也可以從 Windows 中的多個進程打開和讀取臨時文件。 請參閱 Piotr Dobrogost 的回答。
在with
語句中使用mkstemp()
代替os.fdopen()
可以避免調用close()
:
fd, path = tempfile.mkstemp()
try:
with os.fdopen(fd, 'wb') as fileTemp:
fileTemp.write(someStuff)
# ...run the subprocess and wait for it to complete...
finally:
os.remove(path)
我知道這是一篇很老的帖子,但我認為它在今天是相關的,因為 API 正在發生變化,並且 mktemp 和 mkstemp 等函數正在被 TemporaryFile() 和 TemporaryDirectory() 等函數取代。 我只是想在以下示例中演示如何確保臨時目錄在下游仍然可用:
而不是編碼:
tmpdirname = tempfile.TemporaryDirectory()
並在整個代碼中使用 tmpdirname ,您應該嘗試在 with 語句塊中使用您的代碼,以確保它可用於您的代碼調用......像這樣:
with tempfile.TemporaryDirectory() as tmpdirname:
[do dependent code nested so it's part of the with statement]
如果您在 with 之外引用它,那么它很可能不再可見。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.