tarfile
— 讀取和寫入 tar 歸檔檔案¶
原始碼: Lib/tarfile.py
tarfile
模組可以讀取和寫入 tar 歸檔檔案,包括使用 gzip、bz2 和 lzma 壓縮的歸檔檔案。 使用 zipfile
模組讀取或寫入 .zip
檔案,或使用 shutil 中的更高階函式。
一些事實和資料
支援讀取/寫入 POSIX.1-1988 (ustar) 格式。
支援讀取/寫入 GNU tar 格式,包括 longname 和 longlink 擴充套件,只讀支援所有變體的 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)¶
返回路徑名 name 的
TarFile
物件。 有關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)¶
如果 name 是
tarfile
模組可以讀取的 tar 存檔檔案,則返回True
。name 可以是str
、檔案或類檔案物件。在 3.9 版本中更改: 支援檔案和類檔案物件。
tarfile
模組定義了以下異常
- exception tarfile.CompressionError¶
當不支援壓縮方法或資料無法正確解碼時引發。
- exception tarfile.ExtractError¶
當使用
TarFile.extract()
時出現 非致命 錯誤時引發,但僅在TarFile.errorlevel
== 2
時引發。
- exception tarfile.HeaderError¶
如果
TarInfo.frombuf()
獲取的緩衝區無效,則引發。
- exception tarfile.AbsolutePathError¶
拒絕提取具有絕對路徑的成員時引發。
- exception tarfile.OutsideDestinationError¶
拒絕提取目標目錄外的成員時引發。
- exception tarfile.SpecialFileError¶
拒絕提取特殊檔案(例如裝置或管道)時引發。
- exception tarfile.AbsoluteLinkError¶
拒絕提取具有絕對路徑的符號連結時引發。
- exception tarfile.LinkOutsideDestinationError¶
拒絕提取指向目標目錄外部的符號連結時引發。
以下常量在模組級別可用
- tarfile.ENCODING¶
預設字元編碼:在 Windows 上為
'utf-8'
,否則為sys.getfilesystemencoding()
返回的值。
以下每個常量定義了 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_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.getnames()¶
以名稱列表的形式返回成員。它的順序與
getmembers()
返回的列表順序相同。
- TarFile.list(verbose=True, *, members=None)¶
將目錄表列印到
sys.stdout
。如果 verbose 為False
,則僅列印成員的名稱。如果為True
,則會生成類似於 ls -l 的輸出。如果給出了可選的 members,它必須是getmembers()
返回的列表的子集。3.5 版本更改: 添加了 members 引數。
- TarFile.extractall(path='.', members=None, *, numeric_owner=False, filter=None)¶
將歸檔檔案的所有成員提取到當前工作目錄或目錄 path。如果給出了可選的 members,它必須是
getmembers()
返回的列表的子集。目錄資訊(如所有者、修改時間和許可權)會在所有成員提取完畢後設置。這樣做是為了解決兩個問題:每次在目錄中建立檔案時,都會重置目錄的修改時間。而且,如果目錄的許可權不允許寫入,則將檔案提取到目錄中將失敗。如果 numeric_owner 為
True
,則使用 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_owner 和 filter 引數與
extractall()
的相同。註解
extract()
方法不處理幾個提取問題。在大多數情況下,你應該考慮使用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
(預設值),則在不帶 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 命名,或指定為具有檔案描述符的 檔案物件 fileobj。name 可以是 路徑類物件。如果給定 arcname,則指定歸檔檔案中該檔案的替代名稱,否則,該名稱將取自 fileobj 的name
屬性或 name 引數。該名稱應為文字字串。在使用
addfile()
新增之前,您可以修改某些TarInfo
的屬性。如果該檔案物件不是位於檔案開頭的普通檔案物件,則可能需要修改諸如size
之類的屬性。對於諸如GzipFile
之類的物件,情況就是如此。name
也可以修改,在這種情況下,arcname 可以是一個虛擬字串。在 3.6 版本中更改: name 引數接受 路徑類物件。
TarInfo 物件¶
TarInfo
物件表示 TarFile
中的一個成員。除了儲存檔案的所有必需屬性(如檔案型別、大小、時間、許可權、所有者等)之外,它還提供了一些有用的方法來確定其型別。它不包含檔案的資料本身。
TarInfo
物件由 TarFile
的方法 getmember()
, getmembers()
和 gettarinfo()
返回。
修改由 getmember()
或 getmembers()
返回的物件將會影響後續對該存檔的所有操作。如果這是不需要的,你可以使用 copy.copy()
或者呼叫 replace()
方法來一步建立一個修改後的副本。
可以把幾個屬性設定為 None
來表明一塊元資料未使用或未知。不同的 TarInfo
方法會以不同的方式處理 None
。
extract()
或extractall()
方法將會忽略對應的元資料,將其設定為預設值。addfile()
將會失敗。list()
將會列印一個佔位符字串。
- classmethod TarInfo.frombuf(buf, encoding, errors)¶
從字串緩衝區 buf 建立並返回一個
TarInfo
物件。如果緩衝區無效,則引發
HeaderError
。
- TarInfo.tobuf(format=DEFAULT_FORMAT, encoding=ENCODING, errors='surrogateescape')¶
從
TarInfo
物件建立一個字串緩衝區。有關引數的資訊,請參見TarFile
類的建構函式。在 3.2 版本中更改: 將
'surrogateescape'
用作 errors 引數的預設值。
一個 TarInfo
物件有以下公共資料屬性
- 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¶
目標檔名的名稱,它僅存在於型別為
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.sparse¶
稀疏成員資訊。
- 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
物件還提供一些方便的查詢方法
提取過濾器¶
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
。
返回修改後的
TarInfo
成員。
- tarfile.data_filter(member, path)¶
實現
'data'
過濾器。除了tar_filter
所做的之外拒絕 提取連結到絕對路徑或連結到目標外部的連結(硬連結或軟連結)。
這將引發
AbsoluteLinkError
或LinkOutsideDestinationError
。請注意,即使在不支援符號連結的平臺上,也會拒絕此類檔案。
拒絕 提取裝置檔案(包括管道)。這將引發
SpecialFileError
。對於常規檔案,包括硬連結
對於其他檔案(目錄),將
mode
設定為None
,以便提取方法跳過應用許可權位。將使用者和組資訊(
uid
、gid
、uname
、gname
)設定為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
命令列選項¶
- -e <tarfile> [<output_dir>]¶
- --extract <tarfile> [<output_dir>]¶
如果未指定 output_dir ,則將 tar 檔案提取到當前目錄。
- -v, --verbose¶
詳細輸出。
示例¶
如何將整個 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
類的 encoding 和 errors 關鍵字引數控制。
encoding 定義用於存檔中元資料的字元編碼。預設值為 sys.getfilesystemencoding()
或 'ascii'
作為後備。根據存檔是讀取還是寫入,元資料必須解碼或編碼。如果未正確設定 encoding,則此轉換可能會失敗。
errors 引數定義如何處理無法轉換的字元。可能的取值列在 錯誤處理程式 部分中。預設方案是 'surrogateescape'
,Python 也將其用於其檔案系統呼叫,請參閱 檔名,命令列引數和環境變數。
對於 PAX_FORMAT
存檔(預設),通常不需要 encoding,因為所有元資料都使用 UTF-8 儲存。encoding 僅在極少數情況下使用,例如解碼二進位制 pax 標頭或儲存帶有代理字元的字串時。