# `tarfile` --- 讀取與寫入 tar 封存檔案

原始碼：Lib/tarfile.py

`tarfile` 模組用於讀取與寫入 tar 封存檔案，包括使用 gzip、bz2 和 lzma 壓縮的檔案。使用 `zipfile` 模組來讀取或寫入 `.zip` 檔案，或使用 shutil 中的更高階函式。

一些事實和數據：

- 若相對應的模組可用，則可讀取與寫入 `gzip`、`bz2`、`compression.zstd` 和 `lzma` 壓縮的封存檔。

  如果你的 CPython 副本中缺少這些選用模組 (optional modules)，請查閱你的發行者（即提供 Python 給你的人）的文件。如果你就是發行者，請參閱 可選模組的需求。

- 支援 POSIX.1-1988 (ustar) 格式的讀取與寫入。

- 支援 GNU tar 格式的讀取與寫入，包括 longname 和 longlink 擴充功能，以及所有 sparse 擴充功能變體的唯讀支援，包括還原稀疏檔案 (sparse files)。

- 支援 POSIX.1-2001 (pax) 格式的讀取與寫入。

- 處理目錄、一般檔案、硬連結 (hardlinks)、符號連結 (symbolic links)、fifos、字元裝置 (character devices) 和區塊裝置 (block devices)，並能夠取得與還原檔案資訊，如時間戳記、存取權限和擁有者。

在 3.3 版的變更: 新增對 `lzma` 壓縮的支援。

在 3.12 版的變更: 解壓縮封存檔時會使用篩選器 (filter)，你可以用它來限制一些意外或危險的功能，或是明確表示這些功能是你預期的，而且封存檔是完全可信任的。

在 3.14 版的變更: 將預設解壓縮篩選器設為 `data`，這會禁止一些危險的功能，例如指向絕對路徑或目的地之外路徑的連結。在此之前，篩選器策略等同於 `fully_trusted`。

在 3.14 版的變更: 新增對 Zstandard 壓縮的支援（使用 `compression.zstd`）。

tarfile.open(name=None, mode='r', fileobj=None, bufsize=10240, **kwargs)

  回傳路徑名稱 name 的 `TarFile` 物件。關於 `TarFile` 物件與允許的關鍵字引數的詳細資訊，請參閱 TarFile 物件。

  mode 必須是 `'filemode[:compression]'` 形式的字串，預設為 `'r'`。以下是所有可能的模式組合：

  模式 | 操作
  --- | ---
  `'r'` 或 `'r:*'` | 開啟以讀取，自動偵測壓縮格式（建議使用）。
  `'r:'` | 開啟以讀取未壓縮的檔案。
  `'r:gz'` | 開啟以讀取 gzip 壓縮的檔案。
  `'r:bz2'` | 開啟以讀取 bzip2 壓縮的檔案。
  `'r:xz'` | 開啟以讀取 lzma 壓縮的檔案。
  `'r:zst'` | 開啟以讀取 Zstandard 壓縮的檔案。
  `'x'` 或 `'x:'` | 建立一個不壓縮的 tarfile（獨佔模式）。如果檔案已存在，則引發 `FileExistsError` 例外。
  `'x:gz'` | 建立一個使用 gzip 壓縮的 tar 檔案。如果檔案已存在則引發 `FileExistsError` 例外。
  `'x:bz2'` | 建立一個使用 bzip2 壓縮的 tar 檔案。如果檔案已存在，則引發 `FileExistsError` 例外。
  `'x:xz'` | 建立一個使用 lzma 壓縮的 tar 檔案。如果檔案已存在，則引發 `FileExistsError` 例外。
  `'x:zst'` | 建立一個使用 Zstandard 壓縮的 tar 檔案。如果檔案已存在，則引發 `FileExistsError` 例外。
  `'a'` 或 `'a:'` | 開啟以附加內容且不使用壓縮。如果檔案不存在則建立它。
  `'w'` 或 `'w:'` | 開啟以寫入未壓縮的內容。
  `'w:gz'` | 開啟以進行 gzip 壓縮寫入。
  `'w:bz2'` | 開啟以進行 bzip2 壓縮寫入。
  `'w:xz'` | 開啟以進行 lzma 壓縮寫入。
  `'w:zst'` | 開啟以進行 Zstandard 壓縮寫入。

  請注意 `'a:gz'`、`'a:bz2'` 或 `'a:xz'` 是不可能的。如果 mode 不適合開啟特定（壓縮）檔案以進行讀取，則會引發 `ReadError`。使用 mode `'r'` 可避免此問題。如果不支援某個壓縮方法，則會引發 `CompressionError`。

  如果指定了 fileobj，則它會被用作 name 以二進位模式開啟的檔案物件 的替代方案。它應該位於位置 0。

  For modes `'w:gz'`, `'x:gz'`, `'w|gz'`, `'w:bz2'`, `'x:bz2'`, `'w|bz2'`, `tarfile.open()` accepts the keyword argument compresslevel (default `6`) to specify the compression level of the file.

  對於模式 `'w:xz'`、`'x:xz'` 和 `'w|xz'`，`tarfile.open()` 接受關鍵字引數 preset 來指定檔案的壓縮等級。

  對於模式 `'w:zst'`、`'x:zst'` 和 `'w|zst'`，`tarfile.open()` 接受關鍵字引數 level 來指定檔案的壓縮等級。也可以傳遞關鍵字引數 options，提供由 `CompressionParameter` 描述的進階 Zstandard 壓縮參數。可以傳遞關鍵字引數 zstd_dict 以提供 `ZstdDict`，這是一個用於改善較小資料量壓縮效果的 Zstandard 字典。

  For modes `'w:gz'` and `'w|gz'`, `tarfile.open()` accepts the keyword argument mtime to create a gzip archive header with that mtime. By default, the mtime is set to the time of creation of the archive. Use mtime `0` to generate a compressed stream that does not depend on creation time, for reproducible output.

  對於特殊用途，mode 有第二種格式：`'filemode|[compression]'`。`tarfile.open()` 會回傳一個 `TarFile` 物件，該物件將其資料作為區塊串流處理。不會對檔案進行隨機尋找。如果提供了 fileobj，它可以是任何具有 `read()` 或 `write()` 方法（取決於 mode）且能處理位元組的物件。bufsize 指定區塊大小，預設為 `20 * 512` 位元組。此變體可與 `sys.stdin.buffer`、socket 檔案物件 或磁帶裝置等結合使用。但是，這樣的 `TarFile` 物件受到限制，因為它不允許隨機存取，請參閱 範例。目前可能的模式：

  模式 | 操作
  --- | ---
  `'r|*'` | 開啟以讀取 tar 區塊的串流，自動偵測壓縮格式。
  `'r|'` | 開啟以讀取未壓縮的 tar 區塊串流。
  `'r|gz'` | 開啟以讀取 gzip 壓縮的串流。
  `'r|bz2'` | 開啟以讀取 bzip2 壓縮的串流。
  `'r|xz'` | 開啟以讀取 lzma 壓縮的串流。
  `'r|zst'` | 開啟以讀取 Zstandard 壓縮的串流。
  `'w|'` | 開啟以寫入未壓縮的串流。
  `'w|gz'` | 開啟以寫入 gzip 壓縮的串流。
  `'w|bz2'` | 開啟以寫入 bzip2 壓縮的串流。
  `'w|xz'` | 開啟以寫入 lzma 壓縮的串流。
  `'w|zst'` | 開啟以寫入 Zstandard 壓縮的串流。

  在 3.5 版的變更: 新增了 `'x'`（獨佔建立）模式。

  在 3.6 版的變更: name 參數接受類路徑物件。

  在 3.12 版的變更: compresslevel 關鍵字引數也適用於串流。

  在 3.14 版的變更: preset 關鍵字引數也適用於串流。

  在 3.15 版的變更: The default compression level was reduced to 6 (down from 9). It is the default level used by most compression tools and a better tradeoff between speed and performance.

class tarfile.TarFile

  用於讀取和寫入 tar 封存檔的類別。請勿直接使用此類別：請改用 `tarfile.open()`。請參閱 TarFile 物件。

tarfile.is_tarfile(name)

  如果 name 是一個 `tarfile` 模組可以讀取的 tar 封存檔，則回傳 `True`。name 可以是 `str`、檔案或類檔案物件。

  在 3.9 版的變更: 對檔案和類檔案物件的支援。

`tarfile` 模組定義了以下例外：

exception tarfile.TarError

  所有 `tarfile` 例外的基底類別。

exception tarfile.ReadError

  當開啟的 tar 封存檔無法被 `tarfile` 模組處理或以某種方式無效時引發。

exception tarfile.CompressionError

  當壓縮方法不被支援或資料無法正確解碼時引發。

exception tarfile.StreamError

  當遇到類似串流的 `TarFile` 物件的典型限制時引發。

exception tarfile.ExtractError

  在使用 `TarFile.extract()` 時針對非致命錯誤引發，但僅限於 `TarFile.errorlevel``== 2` 時。

exception tarfile.HeaderError

  如果 `TarInfo.frombuf()` 得到的緩衝區無效，則引發此例外。

exception tarfile.FilterError

  被篩選器拒絕的成員的基底類別。

  tarinfo

    篩選器拒絕解壓縮的成員資訊，以 TarInfo 表示。

exception tarfile.AbsolutePathError

  當拒絕解壓縮具有絕對路徑的成員時引發。

exception tarfile.OutsideDestinationError

  當拒絕解壓縮位於目的地目錄之外的成員時引發。

exception tarfile.SpecialFileError

  當拒絕解壓縮特殊檔案（例如裝置或管道）時引發。

exception tarfile.AbsoluteLinkError

  當拒絕解壓縮具有絕對路徑的符號連結時引發。

exception tarfile.LinkOutsideDestinationError

  當拒絕解壓縮指向目的地目錄之外的符號連結時引發。

exception tarfile.LinkFallbackError

  當透過解壓縮另一個封存檔成員來模擬連結（硬連結或符號連結）時，如果該成員會被篩選器位置拒絕，則引發此例外。用於拒絕替代成員的例外可作為 `BaseException.__context__` 取得。

  在 3.15 版被加入.

以下常數可在模組層級使用：

tarfile.ENCODING

  預設字元編碼：在 Windows 上為 `'utf-8'`，否則為 `sys.getfilesystemencoding()` 回傳的值。

tarfile.REGTYPE
tarfile.AREGTYPE

  一個普通檔案 `type`。

tarfile.LNKTYPE

  一個連結（在 tar 檔案內）`type`。

tarfile.SYMTYPE

  一個符號連結 `type`。

tarfile.CHRTYPE

  一個字元特殊裝置 `type`。

tarfile.BLKTYPE

  一個區塊特殊裝置 `type`。

tarfile.DIRTYPE

  一個目錄 `type`。

tarfile.FIFOTYPE

  一個 FIFO 特殊裝置 `type`。

tarfile.CONTTYPE

  一個連續檔案 `type`。

tarfile.GNUTYPE_LONGNAME

  一個 GNU tar longname `type`。

tarfile.GNUTYPE_LONGLINK

  一個 GNU tar longlink `type`。

tarfile.GNUTYPE_SPARSE

  一個 GNU tar 稀疏檔案 `type`。

以下每個常數定義了 `tarfile` 模組能夠建立的 tar 封存檔格式。詳細資訊請參閱 支援的 tar 格式 一節。

tarfile.USTAR_FORMAT

  POSIX.1-1988 (ustar) 格式。

tarfile.GNU_FORMAT

  GNU tar 格式。

tarfile.PAX_FORMAT

  POSIX.1-2001 (pax) 格式。

tarfile.DEFAULT_FORMAT

  建立封存檔的預設格式。目前為 `PAX_FORMAT`。

  在 3.8 版的變更: 新封存檔的預設格式已從 `GNU_FORMAT` 變更為 `PAX_FORMAT`。

也參考

`zipfile` 模組

  `zipfile` 標準模組的文件。

Archiving operations

  標準 `shutil` 模組所提供的更高階封存功能的文件。

GNU tar 手冊，基本 Tar 格式

  tar 封存檔案的文件，包括 GNU tar 擴充功能。

## TarFile 物件

`TarFile` 物件提供一個 tar 封存檔的介面。tar 封存檔是一個區塊序列。一個封存檔成員（一個儲存的檔案）由一個標頭區塊和後續的資料區塊組成。可以在 tar 封存檔中多次儲存一個檔案。每個封存檔成員由一個 `TarInfo` 物件表示，詳細資訊請參閱 TarInfo 物件。

`TarFile` 物件可以在 `with` 陳述式中用作情境管理器。當區塊完成時，它會自動關閉。請注意，如果發生例外，以寫入方式開啟的封存檔將不會被最終化 (finalized)；只有內部使用的檔案物件會被關閉。使用案例請參閱 範例 一節。

在 3.2 版被加入: 新增對情境管理協定的支援。

class tarfile.TarFile(name=None, mode='r', fileobj=None, format=DEFAULT_FORMAT, tarinfo=TarInfo, dereference=False, ignore_zeros=False, encoding=ENCODING, errors='surrogateescape', pax_headers=None, debug=0, errorlevel=1, stream=False)

  以下所有引數都是可選的，也可以作為實例屬性存取。

  name 是封存檔的路徑名稱。name 可以是類路徑物件。如果提供了 fileobj 則可以省略它。在這種情況下，如果檔案物件的 `name` 屬性存在，則會使用該屬性。

  mode 可以是 `'r'` 以從現有封存檔讀取、`'a'` 以附加資料到現有檔案、`'w'` 以建立新檔案覆蓋現有檔案，或 `'x'` 以僅在檔案不存在時建立新檔案。

  如果提供了 fileobj，它會被用於讀取或寫入資料。如果可以確定，mode 會被 fileobj 的模式覆蓋。fileobj 將從位置 0 開始使用。

  備註

  當 `TarFile` 關閉時，fileobj 不會被關閉。

  format 控制寫入時的封存檔格式。它必須是在模組層級定義的常數 `USTAR_FORMAT`、`GNU_FORMAT` 或 `PAX_FORMAT` 之一。讀取時，即使單一封存檔中存在不同格式，格式也會自動偵測。

  tarinfo 引數可用於將預設的 `TarInfo` 類別替換為不同的類別。

  如果 dereference 為 `False`，則將符號連結和硬連結新增到封存檔。如果為 `True`，則將目標檔案的內容新增到封存檔。這在不支援符號連結的系統上沒有效果。

  如果 ignore_zeros 為 `False`，則將空區塊視為封存檔的結尾。如果為 `True`，則跳過空的（和無效的）區塊並嘗試取得盡可能多的成員。這僅對讀取串聯或損壞的封存檔有用。

  debug 可設定從 `0`（無偵錯訊息）到 `3`（所有偵錯訊息）。訊息會寫入 `sys.stderr`。

  errorlevel 控制如何處理解壓縮錯誤，請參閱`對應的屬性`。

  encoding 和 errors 引數定義用於讀取或寫入封存檔的字元編碼以及如何處理轉換錯誤。預設設定適用於大多數使用者。深入資訊請參閱 Unicode 議題 一節。

  pax_headers 引數是一個可選的字串字典，如果 format 為 `PAX_FORMAT`，則會作為 pax 全域標頭新增。

  如果 stream 設為 `True`，則讀取封存檔時不會快取封存檔中關於檔案的資訊，從而節省記憶體。

  在 3.2 版的變更: 使用 `'surrogateescape'` 作為 errors 引數的預設值。

  在 3.5 版的變更: 新增了 `'x'`（獨佔建立）模式。

  在 3.6 版的變更: name 參數接受類路徑物件。

  在 3.13 版的變更: 新增 stream 參數。

classmethod TarFile.open(...)

  替代建構函式。`tarfile.open()` 函式實際上是此類別方法的捷徑。

TarFile.getmember(name)

  回傳成員 name 的 `TarInfo` 物件。如果在封存檔中找不到 name，則引發 `KeyError`。

  備註

  如果一個成員在封存檔中出現多次，則假定其最後一次出現是最新版本。

TarFile.getmembers()

  以 `TarInfo` 物件串列的形式回傳封存檔的成員。串列的順序與封存檔中成員的順序相同。

TarFile.getnames()

  以名稱串列的形式回傳成員。其順序與 `getmembers()` 回傳的串列順序相同。

TarFile.list(verbose=True, *, members=None)

  將內容表印出到 `sys.stdout`。如果 verbose 為 `False`，則只印出成員的名稱。如果為 `True`，則產生類似於 ls -l 的輸出。如果提供了可選的 members，它必須是 `getmembers()` 回傳串列的子集合。

  在 3.5 版的變更: 新增 members 參數。

TarFile.next()

  當 `TarFile` 以讀取方式開啟時，以 `TarInfo` 物件的形式回傳封存檔的下一個成員。如果沒有更多成員可用，則回傳 `None`。

TarFile.extractall(path='.', members=None, *, numeric_owner=False, filter=None)

  將所有成員從封存檔解壓縮到目前的工作目錄或目錄 path。如果提供了可選的 members，它必須是 `getmembers()` 回傳串列的子集合。目錄資訊（如擁有者、修改時間和權限）會在所有成員都被解壓縮後設定。這樣做是為了解決兩個問題：每次在目錄中建立檔案時，目錄的修改時間都會被重設。而且，如果目錄的權限不允許寫入，則無法將檔案解壓縮到其中。

  如果 numeric_owner 為 `True`，則使用 tar 檔案中的 uid 和 gid 數字來設定解壓縮檔案的擁有者／群組。否則，使用 tar 檔案中的名稱值。

  filter 引數指定在解壓縮之前如何修改或拒絕 `members`。詳細資訊請參閱 解壓縮篩選器。建議僅在需要特定 tar 功能時或作為 `filter='data'` 以支援預設安全性較低的 Python 版本（3.13 及更低版本）時明確設定此項。

  警告

  切勿在未事先檢查的情況下解壓縮來自不受信任來源的封存檔。

  從 Python 3.14 開始，預設值（`data`）將防止最危險的安全問題。但是，它不會防止所有意外或不安全的行為。詳細資訊請閱讀 解壓縮篩選器 一節。

  在 3.5 版的變更: 新增 numeric_owner 參數。

  在 3.6 版的變更: path 參數接受類路徑物件。

  在 3.12 版的變更: 新增 filter 參數。

  在 3.14 版的變更: filter 參數現在預設為 `'data'`。

TarFile.extract(member, path='', set_attrs=True, *, numeric_owner=False, filter=None)

  使用完整名稱將一個成員從封存檔解壓縮到目前的工作目錄。其檔案資訊會盡可能準確地解壓縮。member 可以是檔案名稱或 `TarInfo` 物件。你可以使用 path 指定不同的目錄。path 可以是類路徑物件。除非 set_attrs 為 false，否則會設定檔案屬性 (owner, mtime, mode)。

  numeric_owner 和 filter 引數與 `extractall()` 相同。

  備註

  `extract()` 方法不處理多個解壓縮問題。在大多數情況下，你應該考慮使用 `extractall()` 方法。

  警告

  切勿在事先檢查之前從不受信任的來源解壓縮封存檔。詳細資訊請參閱 `extractall()` 的警告。

  在 3.2 版的變更: 增加 set_attrs 參數。

  在 3.5 版的變更: 新增 numeric_owner 參數。

  在 3.6 版的變更: path 參數接受類路徑物件。

  在 3.12 版的變更: 新增 filter 參數。

TarFile.extractfile(member)

  以檔案物件的形式從封存檔解壓縮一個成員。member 可以是檔案名稱或 `TarInfo` 物件。如果 member 是一般檔案或連結，則回傳 `io.BufferedReader` 物件。對於所有其他現有成員，回傳 `None`。如果 member 未出現在封存檔中，則引發 `KeyError`。

  在 3.3 版的變更: 回傳 `io.BufferedReader` 物件。

  在 3.13 版的變更: 回傳的 `io.BufferedReader` 物件具有 `mode` 屬性，該屬性始終等於 `'rb'`。

TarFile.errorlevel: int

  如果 errorlevel 為 `0`，則使用 `TarFile.extract()` 和 `TarFile.extractall()` 時會忽略錯誤。然而，當 debug 大於 0 時，它們會在偵錯輸出中顯示為錯誤訊息。如果為 `1`（預設值），所有致命錯誤都會以 `OSError` 或 `FilterError` 例外的形式引發。如果為 `2`，所有非致命錯誤也會以 `TarError` 例外的形式引發。

  某些例外，例如由錯誤的引數型別或資料損壞引起的例外，總是會被引發。

  自訂的解壓縮篩選器應該對致命錯誤引發 `FilterError`，對非致命錯誤引發 `ExtractError`。

  請注意，當引發例外時，封存檔可能已部分解壓縮。清理是使用者的責任。

TarFile.extraction_filter

  在 3.12 版被加入.

  用作 `extract()` 和 `extractall()` 的 filter 引數預設的解壓縮篩選器。

  此屬性可以是 `None` 或可呼叫物件。與 `extract()` 的 filter 引數不同，此屬性不允許使用字串名稱。

  如果 `extraction_filter` 為 `None`（預設值），解壓縮方法將預設使用 `data` 篩選器。

  此屬性可以在實例上設定或在子類別中覆寫。也可以在 `TarFile` 類別本身上設定它以設定全域預設值，儘管由於它會影響 tarfile 的所有使用，最佳做法是僅在頂層應用程式或 `site 組態`中這樣做。要以這種方式設定全域預設值，需要將篩選器函式包裝在 `staticmethod()` 中以防止注入 `self` 引數。

  在 3.14 版的變更: 預設篩選器設為 `data`，這會禁止一些危險的功能，例如指向絕對路徑或目的地之外路徑的連結。在此之前，預設值等同於 `fully_trusted`。

TarFile.add(name, arcname=None, recursive=True, *, filter=None)

  將檔案 name 新增到封存檔。name 可以是任何型別的檔案（目錄、FIFO、符號連結等）。如果提供了 arcname，則為封存檔中的檔案指定替代名稱。預設情況下，目錄會遞迴新增。這可以透過將 recursive 設為 `False` 來避免。遞迴以排序順序新增條目。如果提供了 filter，它應該是一個接受 `TarInfo` 物件引數並回傳變更後的 `TarInfo` 物件的函式。如果它回傳 `None`，則 `TarInfo` 物件將從封存檔中排除。範例請參閱 範例。

  在 3.2 版的變更: 新增 filter 參數。

  在 3.7 版的變更: 遞迴以排序後的順序新增條目。

TarFile.addfile(tarinfo, fileobj=None)

  將 `TarInfo` 物件 tarinfo 新增到封存檔。如果 tarinfo 表示一個非零大小的一般檔案，fileobj 引數應該是二進位檔案，並從中讀取 `tarinfo.size` 位元組並新增到封存檔。你可以直接建立 `TarInfo` 物件，或使用 `gettarinfo()`。

  在 3.13 版的變更: 對於非零大小的一般檔案，必須提供 fileobj。

TarFile.gettarinfo(name=None, arcname=None, fileobj=None)

  從現有檔案的 `os.stat()` 或等效結果建立 `TarInfo` 物件。檔案可以由 name 命名，或指定為具有檔案描述符的檔案物件 fileobj。name 可以是類路徑物件。如果提供了 arcname，則為封存檔中的檔案指定替代名稱，否則，名稱取自 fileobj 的 `name` 屬性或 name 引數。名稱應該是文字字串。

  在使用 `addfile()` 新增之前，你可以修改 `TarInfo` 的某些屬性。如果檔案物件不是位於檔案開頭的普通檔案物件，則可能需要修改諸如 `size` 之類的屬性。這種情況適用於 `GzipFile` 等物件。`name` 也可以被修改，在這種情況下 arcname 可以是一個虛設字串 (dummy string)。

  在 3.6 版的變更: name 參數接受類路徑物件。

TarFile.close()

  關閉 `TarFile`。在寫入模式下，會在封存檔末尾附加兩個結束零區塊。

TarFile.pax_headers: dict

  包含 pax 全域標頭鍵值對的字典。

## TarInfo 物件

`TarInfo` 物件表示 `TarFile` 中的一個成員。除了儲存檔案的所有必要屬性（如檔案型別、大小、時間、權限、擁有者等）之外，它還提供一些有用的方法來確定其型別。它不包含檔案的資料本身。

`TarInfo` 物件由 `TarFile` 的方法 `getmember()`、`getmembers()` 和 `gettarinfo()` 回傳。

修改由 `getmember()` 或 `getmembers()` 回傳的物件將影響封存檔上的所有後續操作。對於不希望出現這種情況的情況，你可以使用 `copy.copy()` 或呼叫 `replace()` 方法來一步建立修改後的副本。

可以將多個屬性設為 `None` 以表示一段中介資料 (metadata) 未被使用或未知。不同的 `TarInfo` 方法會以不同的方式處理 `None`：

- `extract()` 或 `extractall()` 方法將忽略對應的中介資料，使其保持預設值。

- `addfile()` 將失敗。

- `list()` 將印出一個佔位字串 (placeholder string)。

class tarfile.TarInfo(name='')

  建立 `TarInfo` 物件。

classmethod TarInfo.frombuf(buf, encoding, errors)

  從字串緩衝區 buf 建立並回傳 `TarInfo` 物件。

  如果緩衝區無效，則引發 `HeaderError`。

classmethod TarInfo.fromtarfile(tarfile)

  從 `TarFile` 物件 tarfile 讀取下一個成員並將其作為 `TarInfo` 物件回傳。

TarInfo.tobuf(format=DEFAULT_FORMAT, encoding=ENCODING, errors='surrogateescape')

  從 `TarInfo` 物件建立字串緩衝區。關於引數的資訊，請參閱 `TarFile` 類別的建構函式。

  在 3.2 版的變更: 使用 `'surrogateescape'` 作為 errors 引數的預設值。

一個 `TarInfo` 物件具有以下公開資料屬性：

TarInfo.name: str

  封存檔成員的名稱。

TarInfo.size: int

  大小（以位元組為單位）。

TarInfo.mtime: int | float

  自epoch 以來的最後修改時間（以秒為單位），如 `os.stat_result.st_mtime`。

  在 3.12 版的變更: 對於 `extract()` 和 `extractall()`，可以設為 `None`，讓解壓縮跳過套用此屬性。

TarInfo.mode: int

  權限位元 (permission bits)，如 `os.chmod()` 所用。

  在 3.12 版的變更: 對於 `extract()` 和 `extractall()`，可以設為 `None`，讓解壓縮跳過套用此屬性。

TarInfo.type

  檔案類型。type 通常是這些常數之一：`REGTYPE`、`AREGTYPE`、`LNKTYPE`、`SYMTYPE`、`DIRTYPE`、`FIFOTYPE`、`CONTTYPE`、`CHRTYPE`、`BLKTYPE`、`GNUTYPE_SPARSE`。要更方便地確定 `TarInfo` 物件的類型，請使用下面的 `is*()` 方法。

TarInfo.linkname: str

  目標檔案名稱的名稱，僅存在於型別為 `LNKTYPE` 和 `SYMTYPE` 的 `TarInfo` 物件中。

  對於符號連結（`SYMTYPE`），linkname 相對於包含連結的目錄。對於硬連結（`LNKTYPE`），linkname 相對於封存檔的根。

TarInfo.uid: int

  最初儲存此成員的使用者的使用者 ID。

  在 3.12 版的變更: 對於 `extract()` 和 `extractall()`，可以設為 `None`，讓解壓縮跳過套用此屬性。

TarInfo.gid: int

  最初儲存此成員的使用者的群組 ID。

  在 3.12 版的變更: 對於 `extract()` 和 `extractall()`，可以設為 `None`，讓解壓縮跳過套用此屬性。

TarInfo.uname: str

  使用者名稱。

  在 3.12 版的變更: 對於 `extract()` 和 `extractall()`，可以設為 `None`，讓解壓縮跳過套用此屬性。

TarInfo.gname: str

  群組名稱。

  在 3.12 版的變更: 對於 `extract()` 和 `extractall()`，可以設為 `None`，讓解壓縮跳過套用此屬性。

TarInfo.chksum: int

  標頭校驗和 (checksum)。

TarInfo.devmajor: int

  裝置主號碼。

TarInfo.devminor: int

  裝置副號碼。

TarInfo.offset: int

  tar 標頭從這裡開始。

TarInfo.offset_data: int

  檔案的資料從這裡開始。

TarInfo.sparse

  稀疏成員資訊。

TarInfo.pax_headers: dict

  包含關聯的 pax 擴充標頭鍵值對的字典。

TarInfo.replace(name=..., mtime=..., mode=..., linkname=..., uid=..., gid=..., uname=..., gname=..., deep=True)

  在 3.12 版被加入.

  回傳具有給定屬性變更的 `TarInfo` 物件的新副本。例如，要回傳群組名稱設為 `'staff'` 的 `TarInfo`，請使用：

      new_tarinfo = old_tarinfo.replace(gname='staff')

  預設情況下，會進行深度複製。如果 deep 為 false，則複製為淺複製，即 `pax_headers` 和任何自訂屬性與原始 `TarInfo` 物件共用。

`TarInfo` 物件也提供一些方便的查詢方法：

TarInfo.isfile()

  如果 `TarInfo` 物件是一般檔案，則回傳 `True`。

TarInfo.isreg()

  與 `isfile()` 相同。

TarInfo.isdir()

  如果它是一個目錄，則回傳 `True`。

TarInfo.issym()

  如果它是一個符號連結，則回傳 `True`。

TarInfo.islnk()

  如果它是一個硬連結，則回傳 `True`。

TarInfo.ischr()

  如果它是一個字元裝置，則回傳 `True`。

TarInfo.isblk()

  如果它是一個區塊裝置，則回傳 `True`。

TarInfo.isfifo()

  如果它是一個 FIFO，則回傳 `True`。

TarInfo.isdev()

  如果它是一個字元裝置、區塊裝置或 FIFO，則回傳 `True`。

## 解壓縮篩選器

在 3.12 版被加入.

tar 格式是為了捕捉 UNIX-like 檔案系統的所有細節而設計的，這使它非常強大。不幸的是，這些功能使得建立在解壓縮時具有非預期甚至可能是惡意影響的 tar 檔案變得很容易。例如，解壓縮 tar 檔案可以透過各種方式覆寫任意檔案（例如使用絕對路徑、`..` 路徑元件，或影響後續成員的符號連結）。

在大多數情況下，不需要完整功能。因此，tarfile 支援解壓縮篩選器：一種限制功能的機制，從而減輕某些安全性問題。

警告

沒有任何可用的篩選器會阻擋所有危險的封存檔功能。永遠不要在沒有事先檢查的情況下從不受信任的來源解壓縮封存檔。另請參閱 進一步驗證的提示。

也參考

PEP 706

  包含此設計背後的進一步動機和理由。

`TarFile.extract()` 或 `extractall()` 的 filter 引數可以是：

- `'fully_trusted'` 字串：遵守封存檔中指定的所有中介資料。應在使用者完全信任封存檔或實作自己的複雜驗證時使用。

- `'tar'` 字串：遵守大多數 tar 特定功能（即 UNIX-like 檔案系統的功能），但阻擋很可能令人驚訝或惡意的功能。詳見 `tar_filter()`。

- `'data'` 字串：忽略或阻擋大多數 UNIX-like 檔案系統特定功能。用於解壓縮跨平台資料封存檔。詳見 `data_filter()`。

- `None`（預設）：使用 `TarFile.extraction_filter`。

  如果該值也是 `None`（預設值），則會使用 `'data'` 篩選器。

  > 在 3.14 版的變更: 預設篩選器設為 `data`。在此之前，預設等同於 `fully_trusted`。

- 一個可呼叫物件，對於每個解壓縮的成員，會使用描述該成員的 TarInfo 和封存檔解壓縮目的地路徑來呼叫它（即所有成員使用相同的路徑）：

      filter(member: TarInfo, path: str, /) -> TarInfo | None

  此可呼叫物件在每個成員解壓縮之前被呼叫，因此可以考慮磁碟的目前狀態。它可以：

  - 回傳一個 `TarInfo` 物件，該物件將用於替代封存檔中的中介資料，或

  - 回傳 `None`，在此情況下該成員會被跳過，或

  - 引發例外以中止操作或跳過該成員，取決於 `errorlevel`。請注意，當解壓縮被中止時，`extractall()` 可能會留下部分解壓縮的封存檔。它不會嘗試清理。

### 預設具名篩選器

預先定義的具名篩選器可作為函式使用，因此可以在自訂篩選器中重複使用：

tarfile.fully_trusted_filter(member, path)

  回傳未經修改的 member。

  這實作了 `'fully_trusted'` 篩選器。

tarfile.tar_filter(member, path)

  實作 `'tar'` 篩選器。

  - 從檔名中移除開頭的斜線（`/` 和 `os.sep`）。

  - 拒絕解壓縮具有絕對路徑的檔案（在移除斜線後名稱仍是絕對路徑的情況下，例如 Windows 上的 `C:/foo`）。這會引發 `AbsolutePathError`。

  - 拒絕解壓縮其絕對路徑（在跟隨符號連結後）會位於目的地之外的檔案。這會引發 `OutsideDestinationError`。

  - 清除高位模式位元 (setuid, setgid, sticky) 以及群組/其他人的寫入位元（`S_IWGRP` | `S_IWOTH`）。

  回傳修改後的 `TarInfo` 成員。

tarfile.data_filter(member, path)

  實作 `'data'` 篩選器。除了 `tar_filter` 的功能外，還包括：

  - 使用 `os.path.normpath()` 正規化連結目標（`TarInfo.linkname`）。請注意，這會移除內部的 `..` 元件，如果 `TarInfo.linkname` 中的路徑會遍歷符號連結，這可能會改變連結的意義。

  - 拒絕解壓縮指向絕對路徑的連結（硬連結或軟連結），或指向目的地之外的連結。

    這會引發 `AbsoluteLinkError` 或 `LinkOutsideDestinationError`。

    請注意，即使在不支援符號連結的平台上，這類檔案也會被拒絕。

  - 拒絕解壓縮裝置檔案（包括 pipe）。這會引發 `SpecialFileError`。

  - 對於一般檔案，包括硬連結：

    - 設定擁有者的讀取和寫入權限（`S_IRUSR` | `S_IWUSR`）。

    - 如果擁有者沒有執行權限（`S_IXUSR`），則移除群組和其他人的執行權限（`S_IXGRP` | `S_IXOTH`）。

  - 對於其他檔案（目錄），將 `mode` 設為 `None`，讓解壓縮方法跳過套用權限位元。

  - 將使用者和群組資訊 (`uid`, `gid`, `uname`, `gname`) 設為 `None`，讓解壓縮方法跳過設定它們。

  回傳修改後的 `TarInfo` 成員。

  請注意，此篩選器並未阻擋所有危險的封存檔功能。詳細資訊請參閱 進一步驗證的提示。

  在 3.15 版的變更: 連結目標現在會被正規化。

### 篩選器錯誤

當篩選器拒絕解壓縮檔案時，它會引發適當的例外，該例外是 `FilterError` 的子類別。如果 `TarFile.errorlevel` 為 1 或更高，這將中止解壓縮。使用 `errorlevel=0` 時，錯誤將被記錄並跳過該成員，但解壓縮將繼續進行。

### 進一步驗證的提示

即使使用 `filter='data'`，tarfile 也不適合在沒有事先檢查的情況下解壓縮不受信任的檔案。除了其他問題外，預先定義的篩選器不會防止阻斷服務攻擊。使用者應進行額外檢查。

以下是需要考慮的不完整清單：

- 解壓縮到`新的臨時目錄`以防止例如利用預先存在的連結，並使解壓縮失敗後更容易清理。

- 如果不需要符號連結功能，請禁止它。

- 處理不受信任的資料時，請使用外部（例如作業系統層級）的磁碟、記憶體和 CPU 使用量限制。

- 根據字元白名單檢查檔名（以過濾掉控制字元、易混淆字元、外部路徑分隔符號等）。

- 檢查檔名是否具有預期的副檔名（避免點擊時會執行的檔案，或像 Windows 特殊裝置名稱這樣的無副檔名檔案）。

- 限制解壓縮檔案的數量、解壓縮資料的總大小、檔名長度（包括符號連結長度）以及個別檔案的大小。

- 檢查在不區分大小寫的檔案系統上會被遮蔽的檔案。

另請注意：

- Tar 檔案可能包含同一檔案的多個版本。較晚的版本預期會覆蓋較早的版本。此功能對於允許更新磁帶封存檔至關重要，但可能被惡意濫用。

- tarfile 不會防止「即時」資料的問題，例如攻擊者在解壓縮（或封存）進行中時篡改目的地（或來源）目錄。

### 支援舊版 Python

解壓縮篩選器在 Python 3.12 中加入，但可能會作為安全性更新移植到較舊版本。要檢查此功能是否可用，請使用 `hasattr(tarfile, 'data_filter')` 而不是檢查 Python 版本。

以下範例顯示如何支援有此功能和沒有此功能的 Python 版本。請注意，設定 `extraction_filter` 會影響任何後續操作。

- 完全信任的封存檔：

      my_tarfile.extraction_filter = (lambda member, path: member)
      my_tarfile.extractall()

- 如果可用則使用 `'data'` 篩選器，但如果此功能不可用則使用後備的 Python 3.11 的行為（`'fully_trusted'`）：

      my_tarfile.extraction_filter = getattr(tarfile, 'data_filter',
                                             (lambda member, path: member))
      my_tarfile.extractall()

- 使用 `'data'` 篩選器；如果不可用則失敗：

      my_tarfile.extractall(filter=tarfile.data_filter)

  或：

      my_tarfile.extraction_filter = tarfile.data_filter
      my_tarfile.extractall()

- 使用 `'data'` 篩選器；如果不可用則警告：

      if hasattr(tarfile, 'data_filter'):
          my_tarfile.extractall(filter='data')
      else:
          # 當不再需要時移除它
          warn_the_user('Extracting may be unsafe; consider updating Python')
          my_tarfile.extractall()

### 有狀態的解壓縮篩選器範例

雖然 tarfile 的解壓縮方法接受一個簡單的 filter 可呼叫物件，但自訂篩選器可能是具有內部狀態的更複雜物件。將這些寫成情境管理器可能很有用，像這樣使用：

    with StatefulFilter() as filter_func:
        tar.extractall(path, filter=filter_func)

例如，這樣的篩選器可以寫成：

    class StatefulFilter:
        def __init__(self):
            self.file_count = 0

        def __enter__(self):
            return self

        def __call__(self, member, path):
            self.file_count += 1
            return member

        def __exit__(self, *exc_info):
            print(f'{self.file_count} files extracted')

## 命令列介面

在 3.4 版被加入.

`tarfile` 模組提供了簡單的命令列介面來與 tar 封存檔互動。

如果你要建立新的 tar 封存檔，請在 `-c` 選項後指定其名稱，然後列出應包含的檔案名稱：

    $ python -m tarfile -c monty.tar  spam.txt eggs.txt

也可以傳遞目錄：

    $ python -m tarfile -c monty.tar life-of-brian_1979/

如果你要將 tar 封存檔解壓縮到目前目錄，請使用 `-e` 選項：

    $ python -m tarfile -e monty.tar

你也可以透過傳遞目錄名稱，將 tar 封存檔解壓縮到不同的目錄：

    $ python -m tarfile -e monty.tar  other-dir/

若要列出 tar 封存檔中的檔案，請使用 `-l` 選項：

    $ python -m tarfile -l monty.tar

### 命令列選項

-l <tarfile>
--list <tarfile>

  列出 tarfile 中的檔案。

-c <tarfile> <source1> ... <sourceN>
--create <tarfile> <source1> ... <sourceN>

  從來源檔案建立 tarfile。

-e <tarfile> [<output_dir>]
--extract <tarfile> [<output_dir>]

  如果未指定 output_dir，則將 tarfile 解壓縮到目前目錄。

-t <tarfile>
--test <tarfile>

  測試 tarfile 是否有效。

-v, --verbose

  詳細輸出。

--filter <filtername>

  為 `--extract` 指定 filter。詳見 解壓縮篩選器。僅接受字串名稱（即 `fully_trusted`、`tar` 和 `data`）。

## 範例

### 讀取範例

如何將整個 tar 封存檔解壓縮到目前的工作目錄：

    import tarfile
    tar = tarfile.open("sample.tar.gz")
    tar.extractall(filter='data')
    tar.close()

如何使用產生器函式而非串列，來以 `TarFile.extractall()` 解壓縮 tar 封存檔的子集：

    import os
    import tarfile

    def py_files(members):
        for tarinfo in members:
            if os.path.splitext(tarinfo.name)[1] == ".py":
                yield tarinfo

    tar = tarfile.open("sample.tar.gz")
    tar.extractall(members=py_files(tar))
    tar.close()

如何讀取 gzip 壓縮的 tar 封存檔並顯示部分成員資訊：

    import tarfile
    tar = tarfile.open("sample.tar.gz", "r:gz")
    for tarinfo in tar:
        print(tarinfo.name, "is", tarinfo.size, "bytes in size and is ", end="")
        if tarinfo.isreg():
            print("a regular file.")
        elif tarinfo.isdir():
            print("a directory.")
        else:
            print("something else.")
    tar.close()

### 寫入範例

如何從檔案名稱串列建立未壓縮的 tar 封存檔：

    import tarfile
    tar = tarfile.open("sample.tar", "w")
    for name in ["foo", "bar", "quux"]:
        tar.add(name)
    tar.close()

使用 `with` 陳述式的相同範例：

    import tarfile
    with tarfile.open("sample.tar", "w") as tar:
        for name in ["foo", "bar", "quux"]:
            tar.add(name)

如何在 `TarFile.add()` 的 fileobj 參數中使用 `sys.stdout.buffer` 建立封存檔並寫入標準輸出：

    import sys
    import tarfile
    with tarfile.open("sample.tar.gz", "w|gz", fileobj=sys.stdout.buffer) as tar:
        for name in ["foo", "bar", "quux"]:
            tar.add(name)

如何在 `TarFile.add()` 中使用 filter 參數來建立封存檔並重設使用者資訊：

    import tarfile
    def reset(tarinfo):
        tarinfo.uid = tarinfo.gid = 0
        tarinfo.uname = tarinfo.gname = "root"
        return tarinfo
    tar = tarfile.open("sample.tar.gz", "w:gz")
    tar.add("foo", filter=reset)
    tar.close()

## 支援的 tar 格式

使用 `tarfile` 模組可以建立三種 tar 格式：

- POSIX.1-1988 ustar 格式（`USTAR_FORMAT`）。它支援最多 256 個字元的檔名和最多 100 個字元的連結名稱。檔案大小上限為 8 GiB。這是一種老舊且受限的格式，但廣受支援。

- GNU tar 格式（`GNU_FORMAT`）。它支援長檔名和長連結名稱、超過 8 GiB 的檔案以及稀疏檔案。這是 GNU/Linux 系統上的實際標準。`tarfile` 完全支援 GNU tar 對長名稱的擴充，但稀疏檔案僅有唯讀支援。

- POSIX.1-2001 pax 格式（`PAX_FORMAT`）。這是最靈活的格式，幾乎沒有任何限制。它支援長檔名和長連結名稱、大型檔案，並以可攜的方式儲存路徑名稱。現代的 tar 實作（包括 GNU tar、bsdtar/libarchive 和 star）都完全支援擴充的 pax 功能；某些舊的或未維護的函式庫可能不支援，但應將 pax 封存檔視為普遍支援的 ustar 格式。這是目前建立新封存檔的預設格式。

  它透過額外的標頭擴充既有的 ustar 格式，以儲存無法以其他方式儲存的資訊。pax 標頭有兩種類型：擴充標頭（Extended headers）只影響緊接在後的檔案標頭，全域標頭（global headers）則對整個封存檔有效並影響所有後續檔案。為了可攜性，pax 標頭中的所有資料都使用 UTF-8 編碼。

還有一些 tar 格式的變體可以讀取，但無法建立：

- 古老的 V7 格式。這是 Unix 第七版的第一個 tar 格式，只能儲存一般檔案和目錄。名稱不得超過 100 個字元，且沒有使用者/群組名稱資訊。某些封存檔在欄位包含非 ASCII 字元時，標頭檢查碼會計算錯誤。

- SunOS tar 擴充格式。此格式是 POSIX.1-2001 pax 格式的變體，但並不相容。

## Unicode 議題

tar 格式最初是為了在磁帶機上進行備份而設計的，主要著重於保存檔案系統資訊。現今 tar 封存檔常用於檔案發布和透過網路交換封存檔。原始格式（也是所有其他格式的基礎）的一個問題是，它沒有支援不同字元編碼的概念。例如，在 UTF-8 系統上建立的普通 tar 封存檔，如果包含非 ASCII 字元，在 Latin-1 系統上就無法正確讀取。文字中介資料（如檔名、連結名稱、使用者/群組名稱）會顯示為損壞。不幸的是，無法自動偵測封存檔的編碼。pax 格式就是為了解決此問題而設計的。它使用通用字元編碼 UTF-8 來儲存非 ASCII 中介資料。

`tarfile` 中字元轉換的細節由 `TarFile` 類別的 encoding 和 errors 關鍵字引數控制。

encoding 定義封存檔中介資料所使用的字元編碼。預設值為 `sys.getfilesystemencoding()`，若無法取得則使用 `'ascii'` 作為備用。根據封存檔是讀取還是寫入，中介資料必須被解碼或編碼。如果 encoding 設定不當，此轉換可能會失敗。

errors 引數定義如何處理無法轉換的字元。可能的值列於 Error Handlers 一節。預設方案是 `'surrogateescape'`，這也是 Python 用於檔案系統呼叫的方案，參見 File Names, Command Line Arguments, and Environment Variables。

對於 `PAX_FORMAT` 封存檔（預設格式），通常不需要 encoding，因為所有中介資料都使用 UTF-8 儲存。encoding 只在少數情況下使用，例如解碼二進位 pax 標頭或儲存包含代理字元的字串時。