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

   回傳一個可當作臨時儲存區域的*類檔案物件*。建立該檔案使用了與
   "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, delete_on_close=True)

   此函式的操作與 "TemporaryFile()" 完全相同，但存在以下差異：

   * 此函式回傳一個保證在檔案系統中具有可見名稱的檔案。

   * 為了管理指定檔案，它使用 *delete* 和 *delete_on_close* 參數擴充
     "TemporaryFile()" 來指定是否以及如何自動刪除指定檔案。

   回傳的物件始終是一個*類檔案物件*，其 "file" 屬性是底層的真實檔案物
   件。這個類檔案物件可以在 "with" 陳述式中使用，就像普通檔案一樣。臨
   時檔案的名稱可以從回傳的類檔案物件的 :attr:!name` 屬性中取得。在
   Unix 上則與 "TemporaryFile()" 不同，目錄條目不會在檔案建立後立即被
   取消鏈接 (unlink)。

   如果 *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

     * 額外的 open 會共享刪除存取權限（例如，通過使用旗標
       "O_TEMPORARY" 來呼叫 "os.open()"）

     * *delete* 為 true 但 *delete_on_close* 為 false。請注意，在這種
       情況下不共享刪除存取權限的其他 open（例如透過內建的 "open()" 建
       立）必須在退出情境管理器之前關閉，否則情境管理器上的
       "os.unlink()" 呼叫退出將失敗並出現 "PermissionError"。

   在 Windows 上，如果 *delete_on_close* 為 false，並且檔案是在使用者
   缺乏刪除存取權限的目錄中建立的，則情境管理器退出時的 "os.unlink()"
   呼叫將失敗，並引發 "PermissionError"。當 *delete_on_close* 為 true
   時，不會發生這種情況，因為刪除存取權限是由 open 來要求的，如果未授
   予存取權限則會立即失敗。

   （僅）在 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()" 完全相同，但會將資料排存
   (spool) 於在記憶體中，直到檔案大小超過 *max_size*，或檔案的
   "fileno()" 方法被呼叫為止，此時資料會被寫入磁碟，並且之後的操作與
   "TemporaryFile()" 相同。

   rollover()

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

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

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

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

   在 3.11 版的變更: 完全實作 "io.BufferedIOBase" 和 "io.TextIOBase"
   抽象基底類別（取決於指定的是二進位還是文本 *mode*）。

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

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

   name

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

   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.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*)。

   在 3.12 版的變更: "mkdtemp()" 現在都會回傳絕對路徑，即使 *dir* 是相
   對路徑。

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

   回傳一個在呼叫本方法時不存在檔案的絕對路徑。引數 *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
