tempfile — 生成臨時檔案和目錄

原始碼: Lib/tempfile.py


此模組建立臨時檔案和目錄。它適用於所有受支援的平臺。TemporaryFileNamedTemporaryFileTemporaryDirectorySpooledTemporaryFile 是高階介面,提供自動清理並可用作上下文管理器mkstemp()mkdtemp() 是需要手動清理的低階函式。

所有使用者可呼叫的函式和建構函式都接受額外的引數,允許直接控制臨時檔案和目錄的位置和名稱。此模組使用的檔名包含一串隨機字元,這些檔案可以在共享臨時目錄中安全建立。為了保持向後相容性,引數順序有些奇怪;建議使用關鍵字引數以提高畫質晰度。

該模組定義了以下使用者可呼叫項

tempfile.TemporaryFile(mode='w+b', buffering=-1, encoding=None, newline=None, suffix=None, prefix=None, dir=None, *, errors=None)

返回一個可作為臨時儲存區域的類檔案物件。該檔案是使用與 mkstemp() 相同的規則安全建立的。它一關閉(包括物件被垃圾回收時進行的隱式關閉)就會被銷燬。在 Unix 下,該檔案的目錄條目要麼根本不建立,要麼在檔案建立後立即刪除。其他平臺不支援此功能;您的程式碼不應依賴於使用此函式建立的臨時檔案在檔案系統中是否具有可見名稱。

生成的物件可以用作上下文管理器(參見示例)。上下文完成後或檔案物件銷燬時,臨時檔案將從檔案系統中刪除。

mode 引數預設為 'w+b',以便建立的檔案可以在不關閉的情況下進行讀寫。使用二進位制模式是為了使其在所有平臺上行為一致,而無論儲存的資料如何。bufferingencodingerrorsnewline 的解釋與 open() 相同。

dirprefixsuffix 引數的含義和預設值與 mkstemp() 相同。

在 POSIX 平臺上,返回的物件是真正的檔案物件。在其他平臺上,它是一個類檔案物件,其 file 屬性是底層的真實檔案物件。

如果 os.O_TMPFILE 標誌可用且有效(Linux 特有,需要 Linux 核心 3.11 或更高版本),則使用它。

在既不是 Posix 也不是 Cygwin 的平臺上,TemporaryFile 是 NamedTemporaryFile 的別名。

引發帶有引數 fullpath審計事件 tempfile.mkstemp

3.5 版本中有所改變: 如果可用,現在使用 os.O_TMPFILE 標誌。

3.8 版本中有所改變: 添加了 errors 引數。

tempfile.NamedTemporaryFile(mode='w+b', buffering=-1, encoding=None, newline=None, suffix=None, prefix=None, dir=None, delete=True, *, errors=None, delete_on_close=True)

此函式的執行方式與 TemporaryFile() 完全相同,但有以下區別

  • 此函式返回的檔案保證在檔案系統中具有可見名稱。

  • 為了管理命名檔案,它擴充套件了 TemporaryFile() 的引數,增加了 deletedelete_on_close 引數,它們決定了命名檔案是否以及如何自動刪除。

返回的物件始終是一個類檔案物件,其 file 屬性是底層真實檔案物件。這個類檔案物件可以在 with 語句中使用,就像普通檔案一樣。臨時檔案的名稱可以從返回的類檔案物件的 name 屬性中檢索。在 Unix 上,與 TemporaryFile() 不同,目錄條目在檔案建立後不會立即取消連結。

如果 delete 為 True(預設)且 delete_on_close 為 True(預設),則檔案在關閉後立即刪除。如果 delete 為 True 且 delete_on_close 為 False,則檔案僅在上下文管理器退出時刪除,或者在類檔案物件被終結時刪除。在這種情況下,刪除並不總是保證的(參見 object.__del__())。如果 delete 為 False,則 delete_on_close 的值將被忽略。

因此,要使用臨時檔案的名稱在關閉檔案後重新開啟檔案,要麼確保在關閉時不要刪除檔案(將 delete 引數設定為 False),要麼,如果臨時檔案是在 with 語句中建立的,則將 delete_on_close 引數設定為 False。推薦後一種方法,因為它有助於在上下文管理器退出時自動清理臨時檔案。

在臨時檔案仍然開啟時透過其名稱再次開啟檔案的工作方式如下

  • 在 POSIX 上,檔案始終可以再次開啟。

  • 在 Windows 上,請確保至少滿足以下條件之一

    • delete 為 False

    • 額外的開啟共享刪除訪問許可權(例如,透過使用標誌 O_TEMPORARY 呼叫 os.open()

    • delete 為 True 但 delete_on_close 為 False。請注意,在這種情況下,不共享刪除訪問許可權的額外開啟(例如,透過內建 open() 建立的)必須在退出上下文管理器之前關閉,否則在上下文管理器退出時呼叫 os.unlink() 將因 PermissionError 而失敗。

在 Windows 上,如果 delete_on_close 為 False,並且檔案是在使用者缺乏刪除訪問許可權的目錄中建立的,則在上下文管理器退出時呼叫 os.unlink() 將因 PermissionError 而失敗。當 delete_on_close 為 True 時不會發生這種情況,因為開啟時會請求刪除訪問許可權,如果未授予請求的訪問許可權,則會立即失敗。

在 POSIX(僅限)上,被 SIGKILL 突然終止的程序無法自動刪除其建立的任何 NamedTemporaryFiles。

引發帶有引數 fullpath審計事件 tempfile.mkstemp

3.8 版本中有所改變: 添加了 errors 引數。

3.12 版本中有所改變: 添加了 delete_on_close 引數。

class tempfile.SpooledTemporaryFile(max_size=0, mode='w+b', buffering=-1, encoding=None, newline=None, suffix=None, prefix=None, dir=None, *, errors=None)

此類的操作與 TemporaryFile() 完全相同,只是資料在記憶體中緩衝,直到檔案大小超過 max_size,或者直到呼叫檔案的 fileno() 方法,此時內容被寫入磁碟,操作按照 TemporaryFile() 的方式進行。

rollover()

生成的檔案有一個額外的 rollover() 方法,它使檔案無論大小如何都滾動到磁碟檔案。

返回的物件是一個類檔案物件,其 _file 屬性要麼是 io.BytesIOio.TextIOWrapper 物件(取決於指定的是二進位制 mode 還是文字 mode),要麼是真正的檔案物件,具體取決於是否已呼叫 rollover()。此檔案類物件可以在 with 語句中使用,就像普通檔案一樣。

3.3 版本中有所改變: truncate 方法現在接受 size 引數。

3.8 版本中有所改變: 添加了 errors 引數。

3.11 版本中有所改變: 完全實現了 io.BufferedIOBaseio.TextIOBase 抽象基類(取決於指定的是二進位制 mode 還是文字 mode)。

class tempfile.TemporaryDirectory(suffix=None, prefix=None, dir=None, ignore_cleanup_errors=False, *, delete=True)

此類別以與 mkdtemp() 相同的規則安全地建立臨時目錄。生成的物件可以用作上下文管理器(參見示例)。上下文完成後或臨時目錄物件銷燬時,新建立的臨時目錄及其所有內容將從檔案系統中刪除。

name

目錄名稱可以從返回物件的 name 屬性中檢索。當返回物件用作上下文管理器時,如果存在 with 語句中的 as 子句的目標,則 name 將分配給它。

cleanup()

可以透過呼叫 cleanup() 方法顯式清理目錄。如果 ignore_cleanup_errors 為 True,則在顯式或隱式清理期間發生的任何未處理的異常(例如在 Windows 上刪除開啟的檔案時出現 PermissionError)都將被忽略,剩餘的可刪除項將“盡力”刪除。否則,錯誤將在清理發生的任何上下文中引發(cleanup() 呼叫、退出上下文管理器、物件被垃圾回收或直譯器關閉期間)。

delete 引數可用於在退出上下文時停用目錄樹的清理。雖然上下文管理器停用退出上下文時採取的操作可能看起來不尋常,但在除錯期間或當您需要根據其他邏輯有條件地進行清理行為時,它可能很有用。

引發帶有引數 fullpath審計事件 tempfile.mkdtemp

在 3.2 版本加入。

3.10 版本中有所改變: 添加了 ignore_cleanup_errors 引數。

3.12 版本中有所改變: 添加了 delete 引數。

tempfile.mkstemp(suffix=None, prefix=None, dir=None, text=False)

以儘可能最安全的方式建立臨時檔案。假設平臺正確實現了 os.O_EXCL 標誌用於 os.open(),則在檔案建立中沒有競爭條件。檔案僅由建立使用者 ID 可讀寫。如果平臺使用許可權位來指示檔案是否可執行,則該檔案對任何人均不可執行。檔案描述符不被子程序繼承。

TemporaryFile() 不同,mkstemp() 的使用者負責在完成臨時檔案後刪除它。

如果 suffix 不為 None,則檔名將以該字尾結尾,否則沒有後綴。mkstemp() 不在檔名和字尾之間加點;如果需要,請將其放在 suffix 的開頭。

如果 prefix 不為 None,則檔名將以該字首開頭;否則,使用預設字首。預設值是 gettempprefix()gettempprefixb() 的返回值,視情況而定。

如果 dir 不為 None,則檔案將在該目錄中建立;否則,使用預設目錄。預設目錄從平臺相關的列表中選擇,但應用程式使用者可以透過設定 TMPDIRTEMPTMP 環境變數來控制目錄位置。因此,無法保證生成的 檔名具有任何好的特性,例如透過 os.popen() 傳遞給外部命令時不需要引用。

如果 suffixprefixdir 中的任何一個不為 None,它們必須是相同型別。如果它們是位元組串,則返回的名稱將是位元組串而不是字串。如果您想強制返回位元組串值而其他行為保持預設,請傳入 suffix=b''

如果指定了 text 且為 True,則檔案以文字模式開啟。否則(預設),檔案以二進位制模式開啟。

mkstemp() 返回一個元組,其中包含一個開啟檔案的 OS 級別控制代碼(與 os.open() 返回的相同)和該檔案的絕對路徑名,按此順序。

引發帶有引數 fullpath審計事件 tempfile.mkstemp

3.5 版本中有所改變: 現在可以以位元組串形式提供 suffixprefixdir,以獲取位元組串返回值。在此之前,只允許使用字串。suffixprefix 現在接受並預設為 None,以使用適當的預設值。

3.6 版本中有所改變: dir 引數現在接受路徑類物件

tempfile.mkdtemp(suffix=None, prefix=None, dir=None)

以儘可能最安全的方式建立臨時目錄。在目錄的建立中沒有競爭條件。目錄僅由建立使用者 ID 可讀、可寫和可搜尋。

mkdtemp() 的使用者負責在完成臨時目錄及其內容後刪除它們。

prefixsuffixdir 引數與 mkstemp() 的相同。

mkdtemp() 返回新目錄的絕對路徑名。

引發帶有引數 fullpath審計事件 tempfile.mkdtemp

3.5 版本中有所改變: 現在可以以位元組串形式提供 suffixprefixdir,以獲取位元組串返回值。在此之前,只允許使用字串。suffixprefix 現在接受並預設為 None,以使用適當的預設值。

3.6 版本中有所改變: dir 引數現在接受路徑類物件

3.12 版本中有所改變: 即使 dir 是相對路徑,mkdtemp() 現在也始終返回絕對路徑。

tempfile.gettempdir()

返回用於臨時檔案的目錄名稱。這定義了此模組中所有函式的 dir 引數的預設值。

Python 搜尋一個標準目錄列表,以找到一個呼叫使用者可以在其中建立檔案的目錄。該列表是

  1. TMPDIR 環境變數指定的目錄。

  2. TEMP 環境變數指定的目錄。

  3. TMP 環境變數指定的目錄。

  4. 平臺特定的位置

    • 在 Windows 上,目錄 C:\TEMPC:\TMP\TEMP\TMP,按此順序。

    • 在所有其他平臺上,目錄 /tmp/var/tmp/usr/tmp,按此順序。

  5. 作為最後的手段,當前工作目錄。

此搜尋的結果已快取,請參閱下面 tempdir 的描述。

3.10 版本中有所改變: 始終返回一個 str。此前,它會返回任何 tempdir 值,無論型別如何,只要它不是 None

tempfile.gettempdirb()

gettempdir() 相同,但返回值為位元組串。

在 3.5 版本加入。

tempfile.gettempprefix()

返回用於建立臨時檔案的檔名字首。這不包含目錄元件。

tempfile.gettempprefixb()

gettempprefix() 相同,但返回值為位元組串。

在 3.5 版本加入。

該模組使用一個全域性變數來儲存由 gettempdir() 返回的用於臨時檔案的目錄名稱。可以直接設定它來覆蓋選擇過程,但不建議這樣做。此模組中的所有函式都接受一個 dir 引數,可用於指定目錄。這是推薦的方法,不會因更改全域性 API 行為而讓其他不知情的程式碼感到意外。

tempfile.tempdir

當設定為非 None 的值時,此變數定義此模組中定義函式的 dir 引數的預設值,包括其型別,位元組串或字串。它不能是路徑類物件

如果在呼叫上述函式中的任何一個(gettempprefix() 除外)時 tempdirNone(預設),則它會根據 gettempdir() 中描述的演算法進行初始化。

備註

請注意,如果您將 tempdir 設定為位元組值,則會產生一個糟糕的副作用:當未提供顯式型別為 str 的 prefixsuffixdir 引數時,mkstemp()mkdtemp() 的全域性預設返回型別會更改為位元組串。請不要編寫期望或依賴此行為的程式碼。這種尷尬的行為是為了與歷史實現相容而保留的。

示例

以下是 tempfile 模組典型用法的一些示例

>>> import tempfile

# create a temporary file and write some data to it
>>> fp = tempfile.TemporaryFile()
>>> fp.write(b'Hello world!')
# read data from file
>>> fp.seek(0)
>>> fp.read()
b'Hello world!'
# close the file, it will be removed
>>> fp.close()

# create a temporary file using a context manager
>>> with tempfile.TemporaryFile() as fp:
...     fp.write(b'Hello world!')
...     fp.seek(0)
...     fp.read()
b'Hello world!'
>>>
# file is now closed and removed

# create a temporary file using a context manager
# close the file, use the name to open the file again
>>> with tempfile.NamedTemporaryFile(delete_on_close=False) as fp:
...     fp.write(b'Hello world!')
...     fp.close()
... # the file is closed, but not removed
... # open the file again by using its name
...     with open(fp.name, mode='rb') as f:
...         f.read()
b'Hello world!'
>>>
# file is now removed

# create a temporary directory using the context manager
>>> with tempfile.TemporaryDirectory() as tmpdirname:
...     print('created temporary directory', tmpdirname)
>>>
# directory and contents have been removed

已棄用的函式和變數

建立臨時檔案的一種歷史方法是首先使用 mktemp() 函式生成檔名,然後使用此名稱建立檔案。不幸的是,這不安全,因為在呼叫 mktemp() 和第一個程序隨後嘗試建立檔案之間,另一個程序可能會使用此名稱建立檔案。解決方案是將這兩個步驟結合起來並立即建立檔案。這種方法被 mkstemp() 和上述其他函式使用。

tempfile.mktemp(suffix='', prefix='tmp', dir=None)

自 2.3 版本棄用: 請改用 mkstemp()

返回在呼叫時不存在的檔案的絕對路徑名。prefixsuffixdir 引數與 mkstemp() 的引數類似,只是不支援位元組檔名、suffix=Noneprefix=None

警告

使用此函式可能會在您的程式中引入安全漏洞。當您開始處理它返回的檔名時,其他人可能已經搶先一步。mktemp() 的用法可以很容易地替換為 NamedTemporaryFile(),並傳入 delete=False 引數

>>> f = NamedTemporaryFile(delete=False)
>>> f.name
'/tmp/tmptjujjt'
>>> f.write(b"Hello World!\n")
13
>>> f.close()
>>> os.unlink(f.name)
>>> os.path.exists(f.name)
False