tarfile — 讀取和寫入 tar 歸檔檔案

原始碼: Lib/tarfile.py


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

一些事實和資料

  • 如果相應的模組可用,則讀取和寫入 gzipbz2lzma 壓縮的歸檔檔案。

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

  • 支援讀取/寫入 GNU tar 格式,包括 longnamelonglink 擴充套件,只讀支援所有變體的 sparse 擴充套件,包括恢復稀疏檔案。

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

  • 處理目錄、常規檔案、硬連結、符號連結、fifo、字元裝置和塊裝置,並且能夠獲取和恢復檔案資訊,如時間戳、訪問許可權和所有者。

在 3.3 版本中更改: 添加了對 lzma 壓縮的支援。

在 3.12 版本中更改: 歸檔檔案使用 過濾器 提取,這使得可以限制令人驚訝/危險的功能,或者確認它們是預期的並且歸檔檔案是完全受信任的。 預設情況下,歸檔檔案是完全受信任的,但是此預設設定已棄用,並計劃在 Python 3.14 中更改。

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

返回路徑名 nameTarFile 物件。 有關 TarFile 物件和允許的關鍵字引數的詳細資訊,請參閱 TarFile 物件

mode 必須是 'filemode[:compression]' 形式的字串,預設為 'r'。 這是模式組合的完整列表

mode

動作

'r''r:*'

開啟以進行讀取,並進行透明壓縮(推薦)。

'r:'

開啟以進行讀取,並且不進行壓縮。

'r:gz'

開啟以進行讀取,並進行 gzip 壓縮。

'r:bz2'

開啟以進行讀取,並進行 bzip2 壓縮。

'r:xz'

開啟以進行讀取,並進行 lzma 壓縮。

'x''x:'

獨佔建立 tarfile,不進行壓縮。 如果它已存在,則引發 FileExistsError 異常。

'x:gz'

建立使用 gzip 壓縮的 tarfile。 如果它已存在,則引發 FileExistsError 異常。

'x:bz2'

建立使用 bzip2 壓縮的 tarfile。 如果它已存在,則引發 FileExistsError 異常。

'x:xz'

建立使用 lzma 壓縮的 tarfile。 如果它已存在,則引發 FileExistsError 異常。

'a''a:'

開啟以進行追加,不進行壓縮。 如果檔案不存在,則會建立該檔案。

'w''w:'

開啟以進行未壓縮的寫入。

'w:gz'

開啟以進行 gzip 壓縮的寫入。

'w:bz2'

開啟以進行 bzip2 壓縮的寫入。

'w:xz'

開啟以進行 lzma 壓縮的寫入。

請注意,'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'tarfile.open() 接受關鍵字引數 preset 來指定檔案的壓縮級別。

對於特殊目的,mode 還有第二種格式:'filemode|[compression]'tarfile.open() 將返回一個 TarFile 物件,該物件將其資料作為塊流處理。不會對檔案進行隨機查詢。如果給定,fileobj 可以是任何具有 read()write() 方法(取決於 mode)且使用位元組工作的物件。bufsize 指定塊大小,預設為 20 * 512 位元組。將此變體與例如 sys.stdin.buffer、套接字 檔案物件 或磁帶裝置結合使用。但是,這樣的 TarFile 物件在它不允許隨機訪問方面受到限制,請參閱 示例。當前可能的模式

模式

動作

'r|*'

開啟用於讀取的 tar 塊,具有透明壓縮。

'r|'

開啟用於讀取的未壓縮 tar 塊

'r|gz'

開啟用於讀取的 gzip 壓縮

'r|bz2'

開啟用於讀取的 bzip2 壓縮

'r|xz'

開啟用於讀取的 lzma 壓縮

'w|'

開啟用於寫入的未壓縮

'w|gz'

開啟用於寫入的 gzip 壓縮

'w|bz2'

開啟用於寫入的 bzip2 壓縮

'w|xz'

開啟用於寫入的 lzma 壓縮

在 3.5 版本中更改: 添加了 'x'(獨佔建立)模式。

在 3.6 版本中更改: name 引數接受 路徑類物件

在 3.12 版本中更改: compresslevel 關鍵字引數也適用於流。

class tarfile.TarFile

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

tarfile.is_tarfile(name)

如果 nametarfile 模組可以讀取的 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

拒絕提取指向目標目錄外部的符號連結時引發。

以下常量在模組級別可用

tarfile.ENCODING

預設字元編碼:在 Windows 上為 'utf-8',否則為 sys.getfilesystemencoding() 返回的值。

tarfile.REGTYPE
tarfile.AREGTYPE

常規檔案 type

tarfile.LNKTYPE

連結(在 tarfile 內部)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 長名稱 type

一個 GNU tar 長連結 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 標準模組的文件。

歸檔操作

標準 shutil 模組提供的高階歸檔工具的文件。

GNU tar 手冊,基本 Tar 格式

tar 歸檔檔案的文件,包括 GNU tar 擴充套件。

TarFile 物件

TarFile 物件提供了一個 tar 歸檔檔案的介面。tar 歸檔檔案是一個塊序列。一個歸檔成員(儲存的檔案)由一個頭部塊和資料塊組成。一個檔案可以在 tar 歸檔檔案中儲存多次。每個歸檔成員由一個 TarInfo 物件表示,有關詳細資訊,請參閱 TarInfo 物件

TarFile 物件可以在 with 語句中用作上下文管理器。當代碼塊完成時,它將自動關閉。請注意,如果發生異常,為寫入而開啟的歸檔檔案將不會被最終確定;只會關閉內部使用的檔案物件。有關用例,請參閱 示例 部分。

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 功能顯式設定此項。

警告

切勿在未經事先檢查的情況下提取來自不受信任來源的歸檔檔案。可能會在 path 之外建立檔案,例如,具有以 "/" 開頭的絕對檔名或帶有兩個點 ".." 的檔名。

設定 filter='data' 可以防止大多數危險的安全問題,並閱讀 提取過濾器 部分以瞭解詳細資訊。

3.5 版本更改: 添加了 numeric_owner 引數。

3.6 版本更改: path 引數接受 路徑類物件

3.12 版本更改: 添加了 filter 引數。

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

使用其完整名稱,將歸檔檔案的成員提取到當前工作目錄。其檔案資訊將盡可能精確地提取。member 可以是檔名或 TarInfo 物件。你可以使用 path 指定不同的目錄。path 可以是 路徑類物件。除非 set_attrs 為 false,否則會設定檔案屬性(所有者、mtime、模式)。

numeric_ownerfilter 引數與 extractall() 的相同。

註解

extract() 方法不處理幾個提取問題。在大多數情況下,你應該考慮使用 extractall() 方法。

警告

請參閱 extractall() 的警告。

設定 filter='data' 可以防止大多數危險的安全問題,並閱讀 提取過濾器 部分以瞭解詳細資訊。

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(預設值),則在不帶 filter 引數的情況下呼叫提取方法將引發 DeprecationWarning,並回退到 fully_trusted 過濾器,其危險行為與之前的 Python 版本一致。

在 Python 3.14+ 中,保留 extraction_filter=None 將導致提取方法預設使用 data 過濾器。

該屬性可以在例項上設定,也可以在子類中覆蓋。也可以在 TarFile 類本身上設定它以設定全域性預設值,但是,因為它會影響 tarfile 的所有用法,所以最佳做法是僅在頂級應用程式或 site 配置 中這樣做。要以這種方式設定全域性預設值,需要將過濾器函式包裝在 staticmethod() 中,以防止注入 self 引數。

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 可以是一個虛擬字串。

在 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 來表明一塊元資料未使用或未知。不同的 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

許可權位,與 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

目標檔名的名稱,它僅存在於型別為 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

頭部校驗和。

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 的檔案系統的所有詳細資訊,這使其非常強大。不幸的是,這些功能使得建立在提取時具有意外(甚至可能是惡意的)效果的 tar 檔案變得容易。例如,提取 tar 檔案可以透過多種方式覆蓋任意檔案(例如,使用絕對路徑、.. 路徑元件或影響後續成員的符號連結)。

在大多數情況下,不需要全部功能。因此,tarfile 支援提取過濾器:一種限制功能並從而緩解一些安全問題的機制。

另請參閱

PEP 706

包含關於設計的進一步動機和理由。

可以為 TarFile.extract()extractall() 的 *filter* 引數設定為:

  • 字串 'fully_trusted':按檔案中指定的原樣遵守所有元資料。如果使用者完全信任檔案,或者實現自己的複雜驗證,則應使用此選項。

  • 字串 'tar':遵守大多數 *tar* 特有的功能(即類似 UNIX 的檔案系統的功能),但阻止很可能令人驚訝或惡意的功能。有關詳細資訊,請參見 tar_filter()

  • 字串 'data':忽略或阻止大多數特定於類似 UNIX 的檔案系統的功能。適用於提取跨平臺資料檔案。有關詳細資訊,請參見 data_filter()

  • None(預設):使用 TarFile.extraction_filter

    如果它也是 None (預設值),則引發 DeprecationWarning,並回退到 'fully_trusted' 過濾器,其危險行為與之前的 Python 版本匹配。

    在 Python 3.14 中,'data' 過濾器將成為預設過濾器。可以提前切換;請參閱 TarFile.extraction_filter

  • 一個可呼叫物件,將為每個提取的成員呼叫該物件,其中包含描述成員的 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 所做的之外

  • 拒絕 提取連結到絕對路徑或連結到目標外部的連結(硬連結或軟連結)。

    這將引發 AbsoluteLinkErrorLinkOutsideDestinationError

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

  • 拒絕 提取裝置檔案(包括管道)。這將引發 SpecialFileError

  • 對於常規檔案,包括硬連結

    • 設定所有者讀取和寫入許可權(S_IRUSR | S_IWUSR)。

    • 如果所有者沒有執行許可權 (S_IXUSR),則刪除組和其他可執行許可權 (S_IXGRP | S_IXOTH)。

  • 對於其他檔案(目錄),將 mode 設定為 None,以便提取方法跳過應用許可權位。

  • 將使用者和組資訊(uidgidunamegname)設定為 None,以便提取方法跳過設定它。

返回修改後的 TarInfo 成員。

篩選器錯誤

當過濾器拒絕提取檔案時,它將引發適當的異常,即 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:
        # remove this when no longer needed
        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>

列出 tar 檔案中的檔案。

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

從原始檔建立 tar 檔案。

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

如果未指定 output_dir ,則將 tar 檔案提取到當前目錄。

-t <tarfile>
--test <tarfile>

測試 tar 檔案是否有效。

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

如何從檔名列表建立未壓縮的 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)

如何讀取 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()

如何在 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 標頭有兩種風格:擴充套件標頭僅影響後續的檔案標頭,全域性標頭對整個存檔有效,並影響所有後續檔案。出於可移植性的原因,pax 標頭中的所有資料都以 UTF-8 編碼。

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

  • 古老的 V7 格式。這是 Unix 第七版的第一個 tar 格式,僅儲存常規檔案和目錄。名稱不得超過 100 個字元,沒有使用者/組名稱資訊。在帶有非 ASCII 字元的欄位的情況下,一些存檔具有錯誤計算的標頭校驗和。

  • SunOS tar 擴充套件格式。此格式是 POSIX.1-2001 pax 格式的變體,但不相容。

Unicode 問題

tar 格式最初是為了在磁帶驅動器上進行備份而設計的,主要重點是保留檔案系統資訊。如今,tar 存檔通常用於檔案分發和透過網路交換存檔。原始格式(這是所有其他格式的基礎)的一個問題是,它沒有支援不同字元編碼的概念。例如,如果普通 tar 存檔包含非 ASCII 字元,則在 UTF-8 系統上建立的 tar 存檔無法在 Latin-1 系統上正確讀取。文字元資料(如檔名、連結名、使用者/組名稱)將顯示損壞。不幸的是,沒有辦法自動檢測存檔的編碼。pax 格式旨在解決此問題。它使用通用字元編碼 UTF-8 儲存非 ASCII 元資料。

tarfile 中的字元轉換細節由 TarFile 類的 encodingerrors 關鍵字引數控制。

encoding 定義用於存檔中元資料的字元編碼。預設值為 sys.getfilesystemencoding()'ascii' 作為後備。根據存檔是讀取還是寫入,元資料必須解碼或編碼。如果未正確設定 encoding,則此轉換可能會失敗。

errors 引數定義如何處理無法轉換的字元。可能的取值列在 錯誤處理程式 部分中。預設方案是 'surrogateescape',Python 也將其用於其檔案系統呼叫,請參閱 檔名,命令列引數和環境變數

對於 PAX_FORMAT 存檔(預設),通常不需要 encoding,因為所有元資料都使用 UTF-8 儲存。encoding 僅在極少數情況下使用,例如解碼二進位制 pax 標頭或儲存帶有代理字元的字串時。