"tempfile" --- 生成臨時檔案和目錄
*********************************

**原始碼：**Lib/tempfile.py

======================================================================

該 module（模組）用於建立臨時檔案和目錄，它可以在所有有支援的平臺上使
用。"TemporaryFile"、"NamedTemporaryFile"、"TemporaryDirectory" 和
"SpooledTemporaryFile" 是有自動清除功能的高階介面，可作為情境管理器
(context manager) 使用。"mkstemp()" 和 "mkdtemp()" 是低階函式，使用完
畢後需手動清理。

所有可被使用者呼叫的函式和建構函式都帶有可以設定臨時檔案和臨時目錄的路
徑和名稱的引數。此 module 所使用的檔名為一個隨機字元組成的字串，這讓檔
案可以更安全地在共享的臨時目錄中被建立。為了維持向後相容性，引數的順序
會稍微奇怪，所以為了讓程式更容易被理解，建議使用關鍵字引數。

這個 module 定義了以下可供使用者呼叫的項目：

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

   回傳一個可當作臨時儲存區域的 *file-like object*。建立該檔案使用了與
   "mkstemp()" 相同的安全規則。它將在關閉（包括當物件被垃圾回收
   (garbage collect) 時的隱式關閉）後立即銷毀。在 Unix 下，該檔案所在
   的目錄可能根本不被建立、或者在建立檔案後立即就被刪除，其他平臺不支
   援此功能；你的程式不應依賴使用此功能建立的臨時檔案名稱，因為它在檔
   案系統中的名稱有可能是不可見的。

   生成的物件可以作為情境管理器使用（參見 範例）。完成情境或銷毀臨時檔
   案物件後，臨時檔案將從檔案系統中刪除。

   *mode* 參數預設為 "'w+b'"，所以建立的檔案不用關閉就可以讀取或寫入。
   因為用的是二進位制模式，所以無論存的是什麼資料，它在所有平臺上的行
   為都一致。*buffering*、*encoding*、*errors* 和 *newline* 的含義與
   "open()" 中的相同。

   參數 *dir*、*prefix* 和 *suffix* 的含義和預設值都與它們在
   "mkstemp()" 中的相同。

   在 POSIX 平臺上，回傳物件是真實的檔案物件。在其他平臺上，它是一個
   file-like object，它的 "file" 屬性為底層的真實檔案物件。

   如果可用且可運作，則使用 "os.O_TMPFILE" 旗標（僅限於 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)

   此函式執行的操作與 "TemporaryFile()" 幾乎相同，不同之處為確保該臨時
   檔案在檔案系統中具有可見的名稱（在 Unix 上目錄條目不會被 unlink）。
   檔名可以由回傳 file-like object 的 "name" 屬性取得。在臨時檔案仍開
   啟時，是否允許用檔名第二次開啟檔案，在各個平臺上是不同的（在 Unix
   上可以；在 Windows NT 版本以上不行）。如果 *delete* 為 true（預設值
   ），則檔案會在關閉後立即被刪除。該函式回傳的物件始終是 file-like
   object，它的 "file" 屬性是底層的真實檔案物件。file-like object 可以
   像普通檔案一樣在 "with" 陳述句中使用。

   引發一個附帶引數 "fullpath" 的 "tempfile.mkstemp" 稽核事件。

   3.8 版更變: 新增 *errors* 參數。

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

   此類別執行的操作與 "TemporaryFile()" 完全相同，但會將資料排存
   (spool) 於在記憶體中，直到檔案大小超過 *max_size*，或檔案的
   "fileno()" 方法被呼叫為止，此時資料會被寫入磁碟，並且之後的操作與
   "TemporaryFile()" 相同。

   生成的檔案物件有一個額外的方法 "rollover()"，忽略檔案大小並立即將其
   寫入磁碟。

   回傳的物件是 file-like object，它的 "_file" 屬性是 "io.BytesIO" 或
   "io.TextIOWrapper" 物件（取決於指定的是二進位制模式還是文字模式）或
   真實的檔案物件（取決於是否已呼叫 "rollover()"）。file-like object
   可以像普通檔案一樣在 "with" 陳述式中使用。

   3.3 版更變: 現在，檔案的截斷方法 (truncate method) 可接受一個
   "size" 引數。

   3.8 版更變: 新增 *errors* 參數。

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

   此類別會使用與 "mkdtemp()" 相同安全規則來建立一個臨時目錄。回傳物件
   可當作情境管理器使用（參見範例）。在完成情境或銷毀臨時目錄物件時，
   新建立的臨時目錄及其所有內容會從檔案系統中被移除。

   可以從回傳物件的 "name" 屬性中找到的臨時目錄名稱。當回傳的物件用作
   情境管理器時，這個 "name" 會作為 "with" 陳述句中 "as" 子句的目標（
   如果有 as 的話）。

   此目錄可透過呼叫 "cleanup()" 方法來顯式地清理。如果
   *ignore_cleanup_errors* 為 true，則在顯式或隱式清理期間出現的未處理
   例外（例如在 Windows 上移除開啟的檔案而引發的 "PermissionError"）將
   被忽略，並且剩餘的可移除條目會「儘可能」地被刪除。在其他情況下，錯
   誤將在任何情境清理發生時被引發（"cleanup()" 呼叫、退出情境管理器、
   物件被作為垃圾回收或直譯器關閉等）。

   引發一個附帶引數 "fullpath" 的 "tempfile.mkdtemp" 稽核事件。

   3.2 版新加入.

   3.10 版更變: 新增 *ignore_cleanup_errors* 參數。

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

   盡可能以最安全的方式建立一個臨時檔案。假設所在平臺正確實作了
   "os.open()" 的 "os.O_EXCL" 旗標，則建立檔案時不會有 race condition
   （競爭條件）的情況。該檔案只能由建立者讀寫，如果所在平臺用
   permission bit（許可權位元）來表示檔案是否可執行，則沒有人有執行權
   。檔案描述器不會被子行程繼承。

   與 "TemporaryFile()" 不同，"mkstemp()" 使用者用完臨時檔案後需要自行
   將其刪除。

   如果 *suffix* 不是 "None" 則檔名將以該後綴結尾，若為 "None" 則沒有
   後綴。"mkstemp()" 不會在檔名和後綴之間加點 (dot)，如果需要加一個點
   號，請將其放在 *suffix* 的開頭。

   如果 *prefix* 不是 "None" 則檔名將以該字首開頭，若為 "None" 則使用
   預設前綴。預設前綴是 "gettempprefix()" 或 "gettempprefixb()" 函式的
   回傳值（自動呼叫合適的函式）。

   如果 *dir* 不為 "None" 則在指定的目錄建立檔案，若為 "None" 則使用預
   設目錄。預設目錄是從一個相依於平臺的列表中選擇出來的，但是使用者可
   以設定 *TMPDIR*、*TEMP* 或 *TMP* 環境變數來設定目錄的位置。因此，不
   能保證生成的臨時檔案路徑是使用者友善的，比如透過 "os.popen()" 將路
   徑傳遞給外部命令時仍需要加引號 (quoting)。

   如果 *suffix*、*prefix* 和 *dir* 中的任何一個不是 "None"，就要保證
   它們資料型別相同。如果它們是位元組串，則回傳名稱的型別就是位元組串
   而非字串。如果不想遵循預設行為但又想要回傳值是位元組串型別，請傳入
   "suffix=b''"。

   如果指定了 *text* 且為真值，檔案會以文字模式開啟。否則，檔案（預設
   ）以二進位制模式開啟。

   "mkstemp()" 回傳一個 tuple，tuple 中，第一個元素是一個作業系統層級
   (OS-level) 控制代碼，指向一個開啟的檔案（如同 "os.open()" 的回傳值
   ），第二元素是該檔案的絕對路徑。

   引發一個附帶引數 "fullpath" 的 "tempfile.mkstemp" 稽核事件。

   3.5 版更變: 現在，*suffix*、*prefix* 和 *dir* 可以以位元組串型別按
   順序提供，以獲得位元組串型別的回傳值。在之前只允許使用字串。
   *suffix* 和 *prefix* 現在可以接受 "None"，並且預設為 "None" 以使用
   合適的預設值。

   3.6 版更變: *dir* 參數現在可接受一個類路徑物件 (*path-like object*)
   。

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

   盡可能以最安全的方式建立一個臨時目錄，建立該目錄時不會有 race
   condition 的情況，該目錄只能由建立者讀取、寫入和搜尋。

   "mkdtemp()" 的使用者用完臨時目錄後需要自行將其刪除。

   引數 *prefix*、*suffix* 和 *dir* 的含義與它們在 "mkstemp()" 中相同
   。

   "mkdtemp()" 回傳新目錄的絕對路徑。

   引發一個附帶引數 "fullpath" 的 "tempfile.mkdtemp" 稽核事件。

   3.5 版更變: 現在，*suffix*、*prefix* 和 *dir* 可以以位元組串型別按
   順序提供，以獲得位元組串型別的回傳值。在之前只允許使用字串。
   *suffix* 和 *prefix* 現在可以接受 "None"，並且預設為 "None" 以使用
   合適的預設值。

   3.6 版更變: *dir* 參數現在可接受一個類路徑物件 (*path-like object*)
   。

tempfile.gettempdir()

   回傳儲存臨時檔案的目錄名稱。這設定了此 module 所有函式 *dir* 引數的
   預設值。

   Python 搜尋標準目錄列表來找到呼叫者可以在其中建立檔案的目錄。這個列
   表是：

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

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

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

   4. 與平臺相關的位置：

      * 在 Windows 上，目錄依次為 "C:\TEMP"、"C:\TMP"、"\TEMP" 和
        "\TMP"。

      * 在所有其他平臺上，目錄依次為 "/tmp"、"/var/tmp" 和 "/usr/tmp"
        。

   5. 不得已時，使用當前工作目錄。

   搜尋的結果會被 cache（快取）起來，請見下面 "tempdir" 的描述。

   3.10 版更變: 回傳一個字串。在之前的版本中它會回傳任意 "tempdir" 的
   值而不考慮它的型別，只要它不為 "None"。

tempfile.gettempdirb()

   與 "gettempdir()" 相同，但回傳值為位元組串型別。

   3.5 版新加入.

tempfile.gettempprefix()

   回傳用於建立臨時檔案的檔名前綴，它不包含目錄部分。

tempfile.gettempprefixb()

   與 "gettempprefix()" 相同，但回傳值為位元組串型別。

   3.5 版新加入.

此 module 使用一個全域性變數來儲存由 "gettempdir()" 回傳的臨時檔案使用
的目錄路徑。它可被直接設定以覆蓋選擇過程，但不建議這樣做。此 module 中
的所有函式都接受一個 *dir* 引數，它可被用於指定目錄。這是個推薦的做法
，它不會透過改變全域性 API 行為而對其他不預期此行為的程式造成影響。

tempfile.tempdir

   當被設為 "None" 以外的值時，此變數會為此 module 所定義函式的引數
   *dir* 定義預設值，包括確定其型別為位元組串還是字串。它不可以為
   *path-like object*。

   如果在呼叫除 "gettempprefix()" 外的上述任何函式時 "tempdir" 為
   "None" (預設值) 則它會按照 "gettempdir()" 中所描述的演算法來初始化
   。

   備註:

     請注意如果你將 "tempdir" 設為位元組串值，會有一個麻煩的副作用：
     "mkstemp()" 和 "mkdtemp()" 的全域性預設回傳型別會在沒有提供明顯字
     串型別的 "prefix"、"suffix" 或 "dir" 時被改為位元組串。請不要編寫
     預期此行為或依賴於此行為的程式。這個奇怪的行為是為了維持與以往實
     作版本的相容性。


範例
====

以下是 "tempfile" module 的一些常見用法範例：

   >>> 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 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()" 代替。

   回傳一個在呼叫本方法時不存在檔案的絕對路徑。引數 *prefix*、*suffix*
   和 *dir* 與 "mkstemp()" 中所用的類似，除了在於不支援位元組串型別的
   檔名且不支援 "suffix=None" 和 "prefix=None"。

   警告:

     使用此功能可能會在程式中引入安全漏洞。當你開始使用本方法回傳的檔
     案執行任何操作時，可能有人已經捷足先登了。"mktemp()" 的功能可以很
     輕鬆地用帶有 "delete=False" 參數的 "NamedTemporaryFile()" 代替：

        >>> 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
