13.6. tarfile — 读写 tar 归档文件 — Python 文档
13.6. tar文件 — 读写 tar 归档文件
tarfile 模块可以读取和写入 tar 档案,包括使用 gzip、bz2 和 lzma 压缩的档案。 使用 zipfile 模块读取或写入 .zip
文件,或 shutil 中的更高级别函数。
一些事实和数据:
- 如果相应的模块可用,则读取和写入 gzip、bz2 和 lzma 压缩档案。
- 对 POSIX.1-1988 (ustar) 格式的读/写支持。
- 对 GNU tar 格式的读/写支持,包括 longname 和 longlink 扩展,只读支持 sparse 扩展的所有变体,包括稀疏文件的恢复。
- 对 POSIX.1-2001 (pax) 格式的读/写支持。
- 处理目录、常规文件、硬链接、符号链接、fifos、字符设备和块设备,并能够获取和恢复文件信息,如时间戳、访问权限和所有者。
3.3 版更改: 添加了对 lzma 压缩的支持。
- tarfile.open(name=None, mode='r', fileobj=None, bufsize=10240, \*\*kwargs)
为路径名 name 返回一个 TarFile 对象。 有关 TarFile 对象和允许的关键字参数的详细信息,请参阅 TarFile 对象 。
mode 必须是
'filemode[:compression]'
形式的字符串,默认为'r'
。 以下是模式组合的完整列表:模式
行动
'r' or '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' or 'a:'
打开以追加,无压缩。 如果文件不存在,则创建该文件。
'w' or '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'
、'r:gz'
、'w:bz2'
、'r:bz2'
、'x:gz'
、'x:bz2'
、tarfile.open () 接受关键字参数 compresslevel(默认9
)来指定文件的压缩级别。出于特殊目的,模式还有第二种格式:
'filemode|[compression]'
。 tarfile.open() 将返回一个 TarFile 对象,该对象将其数据作为块流处理。 不会对文件进行随机搜索。 如果给定,fileobj 可以是任何具有read()
或write()
方法的对象(取决于 mode)。 bufsize 指定块大小,默认为20 * 512
字节。 将此变体与例如结合使用sys.stdin
、套接字 文件对象 或磁带设备。 然而,这样的 TarFile 对象受到限制,因为它不允许随机访问,请参阅 示例 。 当前可能的模式:模式
行动
*' 打开 tar 块的 流 以使用透明压缩进行读取。
' 打开未压缩的 tar 块的 流 以进行读取。
gz' 打开 gzip 压缩的 stream 进行阅读。
bz2' 打开一个 bzip2 压缩的 stream 进行读取。
xz' 打开一个 lzma 压缩的 stream 进行读取。
' 打开未压缩的 流 进行写入。
gz' 打开一个 gzip 压缩的 stream 进行写入。
bz2' 打开一个 bzip2 压缩的 stream 进行写入。
xz' 打开一个 lzma 压缩的 stream 进行写入。
3.5版本变更:增加了
'x'
(独创)模式。3.6 版更改: name 参数接受 类路径对象 。
- class tarfile.TarFile
- 用于读取和写入 tar 档案的类。 不要直接使用这个类:使用 tarfile.open() 代替。 参见 TarFile 对象 。
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() 引发。
以下常量在模块级别可用:
- 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
- 创建档案的默认格式。 目前是 GNU_FORMAT。
也可以看看
- 模块 zipfile
- zipfile 标准模块的文档。
- 归档操作
- 标准 shutil 模块提供的更高级别归档工具的文档。
- GNU tar 手册,基本 Tar 格式
- tar 存档文件的文档,包括 GNU tar 扩展。
13.6.1. 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=0)
以下所有参数都是可选的,也可以作为实例属性访问。
name 是存档的路径名。 name 可能是一个 类似路径的对象 。 如果给出 fileobj,则可以省略。 在这种情况下,如果存在文件对象的
name
属性,则使用该属性。mode 是
'r'
从现有档案中读取,'a'
将数据附加到现有文件,'w'
创建一个覆盖现有文件的新文件一个,或'x'
仅在新文件不存在时创建新文件。如果给出 fileobj,则用于读取或写入数据。 如果可以确定,则 mode 被 fileobj 的模式覆盖。 fileobj 将从位置 0 开始使用。
笔记
fileobj 不关闭,当 TarFile 关闭时。
format 控制存档格式。 它必须是在模块级别定义的常量 USTAR_FORMAT、GNU_FORMAT 或 PAX_FORMAT 之一。
tarinfo 参数可用于用不同的类替换默认的 TarInfo 类。
如果 dereference 是 False,则将符号链接和硬链接添加到存档。 如果是True,则将目标文件的内容添加到存档中。 这对不支持符号链接的系统没有影响。
如果 ignore_zeros 是 False,则将空块视为存档的结尾。 如果是 True,则跳过空(和无效)块并尝试获取尽可能多的成员。 这仅对读取连接或损坏的档案有用。
debug 可以设置为从
0
(无调试消息)到3
(所有调试消息)。 消息写入sys.stderr
。如果 errorlevel 为
0
,则使用 TarFile.extract() 时会忽略所有错误。 然而,当启用调试时,它们在调试输出中显示为错误消息。 如果1
,则所有 fatal 错误都作为 OSError 异常引发。 如果2
,所有 非致命 错误也会作为 TarError 异常引发。encoding 和 errors 参数定义了用于读取或写入存档的字符编码以及将如何处理转换错误。 默认设置适用于大多数用户。 有关详细信息,请参阅 Unicode 问题 部分。
pax_headers 参数是一个可选的字符串字典,如果 format 是 PAX_FORMAT,它将作为 pax 全局标头添加。
3.2 版更改: 使用
'surrogateescape'
作为 errors 参数的默认值。3.5版本变更:增加了
'x'
(独创)模式。3.6 版更改: name 参数接受 类路径对象 。
- classmethod TarFile.open(...)
- 替代构造函数。 tarfile.open() 函数实际上是这个类方法的快捷方式。
- TarFile.getmember(name)
为成员 name 返回一个 TarInfo 对象。 如果在存档中找不到 name,则会引发 KeyError。
笔记
如果某个成员在存档中出现多次,则假定其最后一次出现是最新版本。
- TarFile.getmembers()
- 将存档成员作为 TarInfo 对象列表返回。 该列表与存档中的成员具有相同的顺序。
- 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)
将存档中的所有成员提取到当前工作目录或目录 path。 如果给出了可选的 members,它必须是由 getmembers() 返回的列表的子集。 在提取所有成员后设置目录信息,如所有者、修改时间和权限。 这样做是为了解决两个问题: 每次在其中创建文件时都会重置目录的修改时间。 而且,如果目录的权限不允许写入,则将文件提取到该目录将失败。
如果 numeric_owner 是 True,则 tarfile 中的 uid 和 gid 编号用于设置提取文件的所有者/组。 否则,将使用 tarfile 中的命名值。
警告
未经事先检查,切勿从不受信任的来源提取档案。 文件可能是在 path 之外创建的,例如 具有以
"/"
开头的绝对文件名或以两个点".."
开头的文件名的成员。3.5 版更改: 添加 numeric_owner 参数。
在 3.6 版更改:path 参数接受一个 path-like object。
- TarFile.extract(member, path=, set_attrs=True, *, numeric_owner=False)
使用其全名从存档中提取成员到当前工作目录。 尽可能准确地提取其文件信息。 member 可以是文件名或 TarInfo 对象。 您可以使用 path 指定不同的目录。 path 可能是一个 path-like object。 除非 set_attrs 为 false,否则设置文件属性(所有者、mtime、模式)。
如果 numeric_owner 是 True,则 tarfile 中的 uid 和 gid 编号用于设置提取文件的所有者/组。 否则,将使用 tarfile 中的命名值。
笔记
extract() 方法不处理几个提取问题。 在大多数情况下,您应该考虑使用 extractall() 方法。
警告
请参阅 extractall() 的警告。
3.2 版更改: 添加 set_attrs 参数。
3.5 版更改: 添加 numeric_owner 参数。
在 3.6 版更改:path 参数接受一个 path-like object。
- TarFile.extractfile(member)
从存档中提取成员作为文件对象。 member 可以是文件名或 TarInfo 对象。 如果 member 是常规文件或链接,则返回 io.BufferedReader 对象。 否则,返回 None。
3.3 版更改: 返回 io.BufferedReader 对象。
- TarFile.add(name, arcname=None, recursive=True, exclude=None, *, filter=None)
将文件 name 添加到存档中。 name 可以是任何类型的文件(目录、fifo、符号链接等)。 如果给定,arcname 指定存档中文件的替代名称。 默认情况下以递归方式添加目录。 这可以通过将 recursive 设置为 False 来避免。 如果给出 exclude,它必须是一个函数,它接受一个文件名参数并返回一个布尔值。 根据这个值,相应的文件要么被排除(True),要么被添加(False)。 如果指定了 filter,则它必须是关键字参数。 它应该是一个接受 TarInfo 对象参数并返回更改后的 TarInfo 对象的函数。 如果它返回 None,则 TarInfo 对象将从存档中排除。 有关示例,请参阅 示例 。
3.2 版更改: 添加 过滤器 参数。
3.2 版后已弃用: exclude 参数已弃用,请改用 filter 参数。
- TarFile.addfile(tarinfo, fileobj=None)
- 将 TarInfo 对象 tarinfo 添加到存档中。 如果给出 fileobj,它应该是一个 二进制文件 ,从中读取
tarinfo.size
字节并添加到存档中。 您可以直接创建 TarInfo 对象,也可以使用 gettarinfo()。
- TarFile.gettarinfo(name=None, arcname=None, fileobj=None)
根据现有文件上的 os.stat() 或等效结果创建 TarInfo 对象。 该文件要么由 name 命名,要么指定为 file object fileobj 和文件描述符。 name 可能是一个 类似路径的对象 。 如果给定,arcname 指定存档中文件的替代名称,否则,名称取自 fileobj 的 name 属性,或 ]name 参数。 名称应为文本字符串。
在使用 addfile() 添加之前,您可以修改 TarInfo 的一些属性。 如果文件对象不是位于文件开头的普通文件对象,可能需要修改size等属性。 对于诸如 GzipFile 之类的对象就是这种情况。 name 也可以修改,在这种情况下 arcname 可能是一个虚拟字符串。
3.6 版更改: name 参数接受 类路径对象 。
- TarFile.close()
- 关闭 TarFile。 在写入模式下,两个完成零块被附加到存档中。
- TarFile.pax_headers
- 包含 pax 全局标头的键值对的字典。
13.6.2. TarInfo 对象
TarInfo 对象代表 TarFile 中的一个成员。 除了存储文件的所有必需属性(如文件类型、大小、时间、权限、所有者等)外,它还提供了一些有用的方法来确定其类型。 它确实 不 包含文件本身的数据。
TarInfo 对象由 TarFile 的方法 getmember()
、getmembers()
和 gettarinfo()
返回。
- class tarfile.TarInfo(name=)
- 创建一个 TarInfo 对象。
- 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.name
- 存档成员的名称。
- TarInfo.size
- 以字节为单位的大小。
- TarInfo.mtime
- 上次修改时间。
- TarInfo.mode
- 权限位。
- TarInfo.type
- 文件类型。 type 通常是以下常量之一:
REGTYPE
、AREGTYPE
、LNKTYPE
、SYMTYPE
、DIRTYPE
、[ X104X]、CONTTYPE
、CHRTYPE
、BLKTYPE
、GNUTYPE_SPARSE
。 要更方便地确定 TarInfo 对象的类型,请使用下面的is*()
方法。
- TarInfo.linkname
- 目标文件名的名称,仅存在于
LNKTYPE
和SYMTYPE
类型的 TarInfo 对象中。
- TarInfo.uid
- 最初存储此成员的用户的用户 ID。
- TarInfo.gid
- 最初存储此成员的用户的组 ID。
- TarInfo.uname
- 用户名。
- TarInfo.gname
- 团队名字。
- TarInfo.pax_headers
- 包含关联 pax 扩展标头的键值对的字典。
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。
13.6.3. 命令行界面
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
13.6.3.1. 命令行选项
- -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
- 详细输出。
13.6.4. 例子
如何将整个 tar 存档解压缩到当前工作目录:
import tarfile
tar = tarfile.open("sample.tar.gz")
tar.extractall()
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()
13.6.5. 支持的 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 实现都能正确处理 pax 档案。
pax 格式是现有 ustar 格式的扩展。 它对无法以其他方式存储的信息使用额外的标头。 pax 头有两种风格:扩展头仅影响后续文件头,全局头对完整存档有效并影响所有后续文件。 出于可移植性的原因,pax 标头中的所有数据都以 UTF-8 编码。
还有一些 tar 格式的变体可以读取,但不能创建:
- 古老的 V7 格式。 这是 Unix 第七版的第一个 tar 格式,仅存储常规文件和目录。 名称不得超过 100 个字符,没有用户/组名称信息。 如果字段包含非 ASCII 字符,某些存档会错误计算标头校验和。
- SunOS tar 扩展格式。 此格式是 POSIX.1-2001 pax 格式的变体,但不兼容。
13.6.6. 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 标头或存储具有代理字符的字符串时的极少数情况。