1. tempfile臨時文件系統對象
要想安全的創建名字唯一的臨時文件,以防止被試圖破壞應用或竊取數據的人猜出,這很有難度。tempfile模塊提供了多個函數來安全的創建臨時文件系統資源。TemporaryFile()打開並返回一個未命名的文件,NamedTemporaryFile()打開並返回一個命名文件,SpooledTemporaryFile在將內容寫入磁盤之前先將其保存在內存中,TemporaryDirectory是一個上下文管理器,上下文關閉時會刪除這個目錄。
1.1 臨時文件
如果應用需要臨時文件來存儲數據,而不需要與其他程序共享這些文件,則應當使用TemporaryFile()函數創建文件。這個函數會創建一個文件,而且如果平台支持,它會立即斷開這個新文件的鏈接。這樣一來,其他程序就不可能找到或打開這個文件,因為文件系統表中根本沒有這個文件的引用。對於TemporaryFile()創建的文件,無論通過調用close()還是結合使用上下文管理器API和with語句,關閉文件時都會自動刪除這個文件。
import os import tempfile print('Building a filename with PID:') filename = '/guess_my_name.{}.txt'.format(os.getpid()) with open(filename, 'w+b') as temp: print('temp:') print(' {!r}'.format(temp)) print('temp.name:') print(' {!r}'.format(temp.name)) # Clean up the temporary file yourself. os.remove(filename) print() print('TemporaryFile:') with tempfile.TemporaryFile() as temp: print('temp:') print(' {!r}'.format(temp)) print('temp.name:') print(' {!r}'.format(temp.name))
這個例子展示了采用不同方法創建臨時文件的差別,一種做法是使用一個通用模式來構造臨時文件的文件名,另一種做法是使用TemporaryFile()函數。TemporaryFile()返回的文件沒有文件名。

默認的,文件句柄是使用模式'w+b'創建的,以便它在所有平台上都表現一致,並允許調用者讀寫這個文件。
import os import tempfile with tempfile.TemporaryFile() as temp: temp.write(b'Some data') temp.seek(0) print(temp.read())
寫文件之后,必需使用seek()"回轉"文件句柄以便從文件讀回數據。

要以文本模式打開文件,創建文件時要設置mode為'w+t'。
import tempfile with tempfile.TemporaryFile(mode='w+t') as f: f.writelines(['first\n', 'second\n']) f.seek(0) for line in f: print(line.rstrip())
這個文件句柄將把數據處理為文本。

1.2 命名文件
有些情況下,可能非常需要一個命名的臨時文件。對於跨多個進程甚至主機的應用來說,為文件命名是在應用不同部分之間傳遞文件的最簡單的方法。NamedTemporaryFile()函數會創建一個文件,但不會斷開它的鏈接,所以會保留它的文件名(用name屬性訪問)。
import os import pathlib import tempfile with tempfile.NamedTemporaryFile() as temp: print('temp:') print(' {!r}'.format(temp)) print('temp.name:') print(' {!r}'.format(temp.name)) f = pathlib.Path(temp.name) print('Exists after close:', f.exists())
句柄關閉后文件將被刪除。

1.3 假脫機文件
如果臨時文件中包含的數據相對較少,則使用SpooledTemporaryFile可能更高效,因為它使用一個io.BytesIO或io.stringIO緩沖區在內存中保存內容,直到數據達到一個閾值時,數據將“滾動”並寫入磁盤,然后用常規的TemporaryFile()替換這個緩沖區。
import tempfile with tempfile.SpooledTemporaryFile(max_size=100, mode='w+t', encoding='utf-8') as temp: print('temp: {!r}'.format(temp)) for i in range(3): temp.write('This line is repeated over and over.\n') print(temp._rolled, temp._file)
這個例子使用SpooledTemporaryFile的私有屬性來確定何時滾動到磁盤。除非要調整緩沖區大小,否則很少需要檢查這個狀態。

要顯示的將緩沖區寫至磁盤,可以調用rollover()或fileno()方法。
import tempfile with tempfile.SpooledTemporaryFile(max_size=1000, mode='w+t', encoding='utf-8') as temp: print('temp: {!r}'.format(temp)) for i in range(3): temp.write('This line is repeated over and over.\n') print(temp._rolled, temp._file) print('rolling over') temp.rollover() print(temp._rolled, temp._file)
在這個例子中,由於緩沖區非常大,遠遠大於實際的數據量,所以除非調用rollover(),否則不會在磁盤上創建任何文件。

1.4 臨時目錄
需要多個臨時文件時,可能更方便的做法是用TemporaryDirectory創建一個臨時目錄,並打開該目錄中的所有文件。
import pathlib import tempfile with tempfile.TemporaryDirectory() as directory_name: the_dir = pathlib.Path(directory_name) print(the_dir) a_file = the_dir / 'a_file.txt' a_file.write_text('This file is deleted.') print('Directory exists after?', the_dir.exists()) print('Contents after:', list(the_dir.glob('*')))
上下文管理器會生成目錄名,可以在上下文塊中用來建立其他文件名。

1.5 臨時文件位置
如果沒有使用dir參數指定明確的目標位置,則臨時文件使用的路徑會根據當前平台和設置而變化。tempfile模塊包括兩個函數來查詢運行時使用的設置。
import tempfile print('gettempdir():', tempfile.gettempdir()) print('gettempprefix():', tempfile.gettempprefix())
gettempdir()返回包含所有臨時文件的默認目錄,gettempprefix()返回新文件和目錄名和字符串前綴。


gettempdir()返回的值根據一個簡單算法來設置,它會查找一個位置列表,尋找第一個允許當前進程創建文件的位置。
import tempfile tempfile.tempdir = '/I/changed/this/path' print('gettempdir():', tempfile.gettempdir())
如果程序需要對所有臨時文件使用一個全局位置,但不使用以上任何環境變量,則應當直接設置tempfile.tempdir,為該變量賦一個值。

