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

原始碼: Lib/tarfile.py


tarfile 模組使得讀取和寫入 tar 歸檔檔案成為可能,包括那些使用 gzip、bz2 和 lzma 壓縮的。使用 zipfile 模組來讀取或寫入 .zip 檔案,或使用 shutil 中的更高級別函式。

一些事實和資料

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

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

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

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

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

3.3 版本中的變化: 添加了對 lzma 壓縮的支援。

3.12 版本中的變化: 歸檔檔案使用 過濾器 進行提取,這使得可以限制令人驚訝/危險的功能,或者承認這些功能是預期並完全信任歸檔檔案。

3.14 版本中的變化: 將預設提取過濾器設定為 data,這禁止了一些危險功能,例如指向絕對路徑或目標目錄之外的路徑的連結。此前,過濾器策略等同於 fully_trusted

3.14 版本中的變化: 添加了使用 compression.zstd 的 Zstandard 壓縮支援。

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

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

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

模式

action

'r''r:*'

以透明壓縮方式開啟以供讀取(推薦)。

'r:'

以獨佔方式開啟以供讀取,不進行壓縮。

'r:gz'

以 gzip 壓縮方式開啟以供讀取。

'r:bz2'

以 bzip2 壓縮方式開啟以供讀取。

'r:xz'

以 lzma 壓縮方式開啟以供讀取。

'r:zst'

以 Zstandard 壓縮方式開啟以供讀取。

'x''x:'

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

'x:gz'

以 gzip 壓縮方式建立 tarfile。如果檔案已存在,則引發 FileExistsError 異常。

'x:bz2'

以 bzip2 壓縮方式建立 tarfile。如果檔案已存在,則引發 FileExistsError 異常。

'x:xz'

以 lzma 壓縮方式建立 tarfile。如果檔案已存在,則引發 FileExistsError 異常。

'x:zst'

以 Zstandard 壓縮方式建立 tarfile。如果檔案已存在,則引發 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、套接字 檔案物件 或磁帶裝置結合使用。然而,這樣的 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 是 tar 歸檔檔案,並且 tarfile 模組可以讀取,則返回 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

常規檔案 型別

tarfile.LNKTYPE

連結(tarfile 內部) 型別

tarfile.SYMTYPE

符號連結 型別

tarfile.CHRTYPE

字元特殊裝置 型別

tarfile.BLKTYPE

塊特殊裝置 型別

tarfile.DIRTYPE

目錄 型別

tarfile.FIFOTYPE

FIFO 特殊裝置 型別

tarfile.CONTTYPE

連續檔案 型別

tarfile.GNUTYPE_LONGNAME

GNU tar 長名稱 型別

GNU tar 長連結 型別

tarfile.GNUTYPE_SPARSE

GNU tar 稀疏檔案 型別

以下每個常量都定義了 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 功能時才明確設定此引數,或者設定為 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,否則會設定檔案屬性(所有者、修改時間、模式)。

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 configuration 中這樣做。要以這種方式設定全域性預設值,過濾器函式需要包裝在 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 指定檔案中檔案的替代名稱,否則,名稱取自 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

紀元 以來,上次修改時間(秒),如 os.stat_result.st_mtime

3.12 版本中的變化: 可設定為 None,用於 extract()extractall(),導致提取跳過應用此屬性。

TarInfo.mode: int

許可權位,如 os.chmod()

3.12 版本中的變化: 可設定為 None,用於 extract()extractall(),導致提取跳過應用此屬性。

TarInfo.type

檔案型別。 type 通常是以下常量之一: REGTYPEAREGTYPELNKTYPESYMTYPEDIRTYPEFIFOTYPECONTTYPECHRTYPEBLKTYPEGNUTYPE_SPARSE。為了更方便地確定 TarInfo 物件的型別,請使用下面的 is*() 方法。

TarInfo.linkname: str

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

對於符號連結(SYMTYPE), linkname 相對於包含該連結的目錄。對於硬連結(LNKTYPE), linkname 相對於歸檔的根目錄。

TarInfo.uid: int

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

3.12 版本中的變化: 可設定為 None,用於 extract()extractall(),導致提取跳過應用此屬性。

TarInfo.gid: int

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

3.12 版本中的變化: 可設定為 None,用於 extract()extractall(),導致提取跳過應用此屬性。

TarInfo.uname: str

使用者名稱。

3.12 版本中的變化: 可設定為 None,用於 extract()extractall(),導致提取跳過應用此屬性。

TarInfo.gname: str

組名。

3.12 版本中的變化: 可設定為 None,用於 extract()extractall(),導致提取跳過應用此屬性。

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 (預設值),則將使用 '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

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

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

  • 對於普通檔案,包括硬連結

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

  • 將使用者和組資訊(uidgidunamegname)設定為 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:
        # 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>

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

指定 --extractfilter。有關詳細資訊,請參見 提取過濾器。只接受字串名稱(即 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 歸檔視為 universally supported 的 ustar 格式。它是新歸檔的當前預設格式。

    它使用額外的標頭擴充套件了現有的 ustar 格式,用於無法以其他方式儲存的資訊。pax 標頭有兩種型別:擴充套件標頭僅影響後續檔案標頭,全域性標頭對整個歸檔有效並影響所有後續檔案。出於可移植性原因,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 引數定義了無法轉換的字元如何處理。可能的值列在 錯誤處理程式 部分。預設方案是 'surrogateescape',Python 也將其用於檔案系統呼叫,參見 檔名、命令列引數和環境變數

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