tarfile — 读取和写入 tar 归档文件¶
源代码: Lib/tarfile.py
tarfile 模块使得读取和写入 tar 归档文件成为可能,包括那些使用 gzip、bz2 和 lzma 压缩的。使用 zipfile 模块来读取或写入 .zip 文件,或使用 shutil 中的更高级别函数。
一些事实和数据
如果相应的模块可用,则读取和写入
gzip、bz2、compression.zstd和lzma压缩的归档文件。支持 POSIX.1-1988 (ustar) 格式的读/写。
支持 GNU tar 格式的读/写,包括 longname 和 longlink 扩展,以及所有 稀疏 扩展变体的只读支持,包括稀疏文件的恢复。
支持 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)¶
返回路径名 name 的
TarFile对象。有关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模块可以读取,则返回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¶
拒绝提取指向目标目录之外的符号链接时引发。
- exception tarfile.LinkFallbackError¶
当通过提取另一个归档成员来模拟链接(硬链接或符号链接)时,如果该成员将被过滤器位置拒绝,则引发此异常。拒绝替换成员所引发的异常可通过
BaseException.__context__获取。在 3.14 版本加入。
以下常量在模块级别可用
- 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 功能时才明确设置此参数,或者设置为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_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 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 指定文件中文件的替代名称,否则,名称取自 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¶
自 纪元 以来,上次修改时间(秒),如
os.stat_result.st_mtime。3.12 版本中的变化: 可设置为
None,用于extract()和extractall(),导致提取跳过应用此属性。
- TarInfo.mode: int¶
权限位,如
os.chmod()。3.12 版本中的变化: 可设置为
None,用于extract()和extractall(),导致提取跳过应用此属性。
- 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 版本中的变化: 可设置为
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.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(默认值),则将使用'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。
返回修改后的
TarInfo成员。
- tarfile.data_filter(member, path)¶
实现了
'data'过滤器。除了tar_filter所做的之外使用
os.path.normpath()规范化链接目标 (TarInfo.linkname)。请注意,这会删除内部..组件,如果TarInfo.linkname中的路径遍历符号链接,则可能会更改链接的含义。拒绝 提取链接到绝对路径或链接到目标外部的链接(硬链接或软链接)。
这会引发
AbsoluteLinkError或LinkOutsideDestinationError。请注意,即使在不支持符号链接的平台上,也会拒绝此类文件。
拒绝 提取设备文件(包括管道)。这会引发
SpecialFileError。对于普通文件,包括硬链接
对于其他文件(目录),将
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: # 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,则将 tarfile 提取到当前目录。
- -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()
如何读取 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 类的 encoding 和 errors 关键字参数控制。
encoding 定义用于归档中元数据的字符编码。默认值为 sys.getfilesystemencoding() 或 'ascii' 作为备用。根据归档是读取还是写入,元数据必须解码或编码。如果未适当设置 encoding,则此转换可能会失败。
errors 参数定义了无法转换的字符如何处理。可能的值列在 错误处理程序 部分。默认方案是 'surrogateescape',Python 也将其用于文件系统调用,参见 文件名、命令行参数和环境变量。
对于 PAX_FORMAT 归档(默认),通常不需要 encoding,因为所有元数据都使用 UTF-8 存储。 encoding 仅在极少数情况下使用,例如解码二进制 pax 标头或存储带有代理字符的字符串时。