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

原始碼:Lib/tarfile.py


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

一些事實和數據:

  • 若相對應的模組可用,則可讀取與寫入 gzipbz2compression.zstdlzma 壓縮的封存檔。

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

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

  • 支援 GNU tar 格式的讀取與寫入,包括 longnamelonglink 擴充功能,以及所有 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)

回傳路徑名稱 nameTarFile 物件。關於 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。

對於模式 'w:gz''x:gz''w|gz''w:bz2''x:bz2''w|bz2'tarfile.open() 接受關鍵字引數 compresslevel(預設為 9)來指定檔案的壓縮等級。

對於模式 '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 字典。

對於特殊用途,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 關鍵字引數也適用於串流。

class tarfile.TarFile

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

tarfile.is_tarfile(name)

如果 name 是一個 tarfile 模組可以讀取的 tar 封存檔,則回傳 Truename 可以是 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.14 版被加入.

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

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

一個 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_FORMATGNU_FORMATPAX_FORMAT 之一。讀取時,即使單一封存檔中存在不同格式,格式也會自動偵測。

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

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

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

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

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

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

pax_headers 引數是一個可選的字串字典,如果 formatPAX_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)

回傳成員 nameTarInfo 物件。如果在封存檔中找不到 name,則引發 KeyError

備註

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

TarFile.getmembers()

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

TarFile.getnames()

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

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

將內容表印出到 sys.stdout。如果 verboseFalse,則只印出成員的名稱。如果為 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_ownerTrue,則使用 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_ownerfilter 引數與 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

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

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

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

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

TarFile.extraction_filter

在 3.12 版被加入.

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

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

如果 extraction_filterNone(預設值),解壓縮方法將預設使用 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 命名,或指定為具有檔案描述符的檔案物件 fileobjname 可以是類路徑物件。如果提供了 arcname,則為封存檔中的檔案指定替代名稱,否則,名稱取自 fileobjname 屬性或 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

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 通常是這些常數之一:REGTYPEAREGTYPELNKTYPESYMTYPEDIRTYPEFIFOTYPECONTTYPECHRTYPEBLKTYPEGNUTYPE_SPARSE。要更方便地確定 TarInfo 物件的類型,請使用下面的 is*() 方法。

TarInfo.linkname: str

目標檔案名稱的名稱,僅存在於型別為 LNKTYPESYMTYPETarInfo 物件中。

對於符號連結(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 中的路徑會遍歷符號連結,這可能會改變連結的意義。

  • 拒絕解壓縮指向絕對路徑的連結(硬連結或軟連結),或指向目的地之外的連結。

    這會引發 AbsoluteLinkErrorLinkOutsideDestinationError

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

  • 拒絕解壓縮裝置檔案(包括 pipe)。這會引發 SpecialFileError

  • 對於一般檔案,包括硬連結:

    • 設定擁有者的讀取和寫入權限(S_IRUSR | S_IWUSR)。

    • 如果擁有者沒有執行權限(S_IXUSR),則移除群組和其他人的執行權限(S_IXGRP | S_IXOTH)。

  • 對於其他檔案(目錄),將 mode 設為 None,讓解壓縮方法跳過套用權限位元。

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

回傳修改後的 TarInfo 成員。

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

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

篩選器錯誤

當篩選器拒絕解壓縮檔案時,它會引發適當的例外,該例外是 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_trustedtardata)。

範例

讀取範例

如何將整個 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 類別的 encodingerrors 關鍵字引數控制。

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 標頭或儲存包含代理字元的字串時。