# 13.6. `tarfile` — 读取与压缩tar文件

源代码： Lib/tarfile.py

`tarfile` 模块用于读取或者压缩tar文件，可针对gzip、bz2或lzma等格式文件进行相关操作。假如希望对`.zip`格式文件进行操作，则应使用`zipfile`模块，或者使用shutil里的高级函数。

一些事实和数字：

- 如果相应的模块可用，则读取并写入`gzip`，`bz2`和`lzma`压缩归档。
- 读/写支持POSIX.1-1988（ustar）格式。
- 对包括longname和longlink扩展的GNU tar格式的读/写支持，对稀疏扩展的所有变体的只读支持，包括恢复稀疏文件。
- 对POSIX.1-2001（pax）格式的读/写支持。
- 处理目录，常规文件，硬链接，符号链接，fifos，字符设备和块设备，并能够获取和恢复文件信息，如时间戳，访问权限和所有者。

在版本3.3中更改：添加对`lzma`压缩的支持。

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

  为路径名名称返回`TarFile`对象。有关`TarFile`对象和允许的关键字参数的详细信息，请参阅TarFile Objects。

  mode必须是`'filemode[:compression]'`形式的字符串，默认为`'r'`。这里是模式组合的完整列表：

  模式 | 行动
  --- | ---
  `'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'`如果模式不适合打开某个（压缩）文件进行读取，则会出现`ReadError`。使用模式 `'r'`可避免此情况。如果不支持压缩方法，则会引发`CompressionError`。

  如果指定fileobj，它将用作名称以二进制模式打开的file object的替代。它应该在位置0。

  For modes `'w:gz'`, `'r:gz'`, `'w:bz2'`, `'r:bz2'`, `'x:gz'`, `'x:bz2'`, `tarfile.open()` accepts the keyword argument compresslevel (default `9`) to specify the compression level of the file.

  对于特殊用途，还有模式的第二种格式：`'filemode|[compression]'`。`tarfile.open()`将返回一个`TarFile`对象，该对象将其数据作为块流处理。不会对文件进行随机搜索。如果给定，fileobj可以是具有`read()`或`write()`方法的任何对象（取决于t5>）。bufsize指定块大小并默认为`20 * 512`字节。使用此变体与例如 `sys.stdin`，套接字file object或磁带设备。然而，这样的`TarFile`对象受限，因为它不允许随机访问，参见Examples。当前可能的模式：

  模式 | 行动
  --- | ---
  `'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'`（独占创建）模式。

class `tarfile.``TarFile`

  读写tar存档的类。不要直接使用这个类：use `tarfile.open()`。请参阅TarFile Objects。

`tarfile.``is_tarfile`(name)

  返回`True`如果名称是tar存档文件，`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归档格式。有关详细信息，请参阅Supported tar formats一节。

`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`标准模块的文档。
Archiving operations
  由标准`shutil`模块提供的高级存档工具的文档。
GNU tar手动，基本tar格式
  tar归档文件的文档，包括GNU tar扩展。

## 13.6.1. TarFile Objects

`TarFile`对象提供了一个tar归档文件的接口。tar归档是一系列块。存档成员（存储文件）由标题块后跟数据块组成。可以将文件存储在tar存档中多次。每个归档成员由`TarInfo`对象表示，有关详细信息，请参阅TarInfo Objects。

`TarFile`对象可以在`with`语句中用作上下文管理器。当块完成时，它将自动关闭。请注意，如果出现例外情况，打开的写作存档将不会最终确定；只有内部使用的文件对象将被关闭。有关用例，请参见Examples部分。

版本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是归档的路径名。如果给出fileobj，则可以省略。在这种情况下，如果文件对象的`name`属性存在，则使用该属性。

  模式是从现有档案读取`'r'`，`'a'`以将数据附加到现有文件，`'w'`创建新文件覆盖现有文件，或`'x'`创建新文件（如果它不存在）。

  如果给定fileobj，则用于读取或写入数据。如果可以确定，fileobj的模式将覆盖模式。fileobj将从位置0开始使用。

  注意

  当`TarFile`关闭时，fileobj未关闭。

  格式控制归档格式。它必须是在模块级定义的常量`USTAR_FORMAT`，`GNU_FORMAT`或`PAX_FORMAT`之一。

  可以使用tarinfo参数替换默认的`TarInfo`类。

  如果解引用为`False`，请向归档添加符号链接和硬链接。如果`True`，请将目标文件的内容添加到归档中。这对不支持符号链接的系统没有影响。

  如果ignore_zeros为`False`，则将空块视为归档的结尾。如果它`True`，则跳过空（和无效）块，并尝试获取尽可能多的成员。这仅对读取级联或损坏的存档有用。

  调试可以从`0`（无调试消息）到`3`（所有调试消息）设置。消息写入`sys.stderr`。

  如果errorlevel为`0`，则使用`TarFile.extract()`时，将忽略所有错误。但是，当调试启用时，它们在调试输出中显示为错误消息。如果`1`，则所有致命错误都会作为`OSError`异常引发。如果`2`，所有非致命错误也会作为`TarError`异常引发。

  编码和错误参数定义要用于读取或写入归档的字符编码，以及如何处理转换错误。默认设置适用于大多数用户。有关详细信息，请参阅Unicode issues一节。

  pax_headers参数是字符串的可选字典，如果格式是`PAX_FORMAT`，则字符串将添加为pax全局标题。

  在版本3.2中已更改：使用`'surrogateescape'`作为错误参数的默认值。

  在版本3.5中已更改：添加了`'x'`（独占创建）模式。

classmethod `TarFile.``open`(...)

  替代构造函数。The `tarfile.open()` function is actually a shortcut to this classmethod.

`TarFile.``getmember`(name)

  返回成员名称的`TarInfo`对象。如果在归档中找不到名称，则会引发`KeyError`。

  注意

  如果成员在归档中出现多次，则其最后一次出现被假定为最新的版本。

`TarFile.``getmembers`()

  将归档的成员作为`TarInfo`对象的列表返回。该列表与存档中的成员具有相同的顺序。

`TarFile.``getnames`()

  返回成员作为他们的名字的列表。它与由`getmembers()`返回的列表具有相同的顺序。

`TarFile.``list`(verbose=True, *, members=None)

  将目录打印到`sys.stdout`。如果verbose是`False`，则只打印成员的名称。如果`True`，则产生类似于ls -l 的输出。如果给出可选的成员，它必须是由`getmembers()`返回的列表的子集。

  在版本3.5中已更改：添加了成员参数。

`TarFile.``next`()

  当打开`TarFile`进行读取时，将归档的下一个成员作为`TarInfo`对象返回。如果没有更多可用，返回`None`。

`TarFile.``extractall`(path=".", members=None, *, numeric_owner=False)

  将归档中的所有成员解压缩到当前工作目录或目录路径。如果给出了可选的成员，它必须是由`getmembers()`返回的列表的子集。在提取所有成员后，设置所有者，修改时间和权限等目录信息。这是为了解决两个问题：目录的修改时间每次在其中创建文件时重置。并且，如果目录的权限不允许写入，则解压缩文件将失败。

  如果numeric_owner为`True`，tarfile中的uid和gid数字用于设置提取的文件的所有者/组。否则，使用来自tarfile的命名值。

  警告

  切勿在未经预先检查的情况下从不可信来源中提取存档。可能在路径之外创建文件，例如具有以`"/"`开头的绝对文件名的成员或具有两个点`".."`的文件名。

  在版本3.5中已更改：添加了numeric_only参数。

`TarFile.``extract`(member, path="", set_attrs=True, *, numeric_owner=False)

  使用其全名将成员从归档提取到当前工作目录。其文件信息尽可能精确地提取。成员可以是文件名或`TarInfo`对象。您可以使用路径指定其他目录。除非set_attrs为false，否则设置文件属性（owner，mtime，mode）。

  如果numeric_owner为`True`，tarfile中的uid和gid数字用于设置提取的文件的所有者/组。否则，使用来自tarfile的命名值。

  注意

  `extract()`方法不处理几个提取问题。在大多数情况下，您应该考虑使用`extractall()`方法。

  警告

  请参阅`extractall()`的警告。

  在版本3.2中已更改：添加了set_attrs参数。

  在版本3.5中已更改：添加了numeric_only参数。

`TarFile.``extractfile`(member)

  从存档中提取成员作为文件对象。成员可以是文件名或`TarInfo`对象。如果成员是常规文件或链接，则会返回`io.BufferedReader`对象。否则，返回`None`。

  在版本3.3中更改：返回`io.BufferedReader`对象。

`TarFile.``add`(name, arcname=None, recursive=True, exclude=None, *, filter=None)

  将文件名称添加到归档中。名称可以是任何类型的文件（目录，fifo，符号链接等）。如果给定，arcname指定归档中文件的备用名称。默认情况下，目录以递归方式添加。这可以通过将递归设置为`False`来避免。如果给出exclude，它必须是一个函数，它需要一个文件名参数并返回一个布尔值。根据此值，相应的文件被排除（`True`）或添加（`False`）。如果指定filter，它必须是一个关键字参数。它应该是一个接受`TarInfo`对象参数并返回更改的`TarInfo`对象的函数。如果它返回`None`，则将从档案中排除`TarInfo`对象。有关示例，请参见Examples。

  在版本3.2中更改：添加了过滤器参数。

  自版本3.2后已弃用： 排除参数已弃用，请改用filter参数。

`TarFile.``addfile`(tarinfo, fileobj=None)

  将`TarInfo`对象tarinfo添加到归档中。如果给定fileobj，它应该是一个binary file，并且从它读取`tarinfo.size`字节并将其添加到归档中。您可以直接创建`TarInfo`对象，也可以使用`gettarinfo()`。

`TarFile.``gettarinfo`(name=None, arcname=None, fileobj=None)

  从现有文件的`os.stat()`或等效结果创建`TarInfo`对象。该文件由名称命名，或者用文件描述器指定为file object fileobj。If given, arcname specifies an alternative name for the file in the archive, otherwise, the name is taken from fileobj’s `name` attribute, or the name argument. 名称应为文本字符串。

  您可以修改某些`TarInfo`的属性，然后使用`addfile()`添加它。如果文件对象不是位于文件开头的普通文件对象，则可能需要修改`size`等属性。对于诸如`GzipFile`的对象就是这种情况。还可以修改`name`，在这种情况下，arcname可以是虚拟字符串。

`TarFile.``close`()

  关闭`TarFile`。在写入模式下，两个完成零块附加到归档。

`TarFile.``pax_headers`

  包含pax全局头的键/值对的字典。

## 13.6.2. TarInfo Objects

`TarInfo`对象表示`TarFile`中的一个成员。除了存储文件的所有必需属性（如文件类型，大小，时间，权限，所有者等）），它提供了一些有用的方法来确定它的类型。它不包含文件的数据本身。

`TarInfo`对象由`TarFile`的方法`getmember()`，`getmembers()`和`gettarinfo()`。

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'`作为错误参数的默认值。

`TarInfo`对象具有以下公共数据属性：

`TarInfo.``name`

  存档成员的名称。

`TarInfo.``size`

  大小（字节）。

`TarInfo.``mtime`

  上次修改时间。

`TarInfo.``mode`

  权限位。

`TarInfo.``type`

  文件类型。类型通常是以下常量之一：`REGTYPE`，`AREGTYPE`，`LNKTYPE`，`SYMTYPE` ，`DIRTYPE`，`FIFOTYPE`，`CONTTYPE`，`CHRTYPE`，`BLKTYPE`，`GNUTYPE_SPARSE`。要更方便地确定`TarInfo`对象的类型，请使用下面的`is*()`方法。

`TarInfo.``linkname`

  目标文件名的名称，只存在于类型`LNKTYPE`和`SYMTYPE`的`TarInfo`对象中。

`TarInfo.``uid`

  最初存储此成员的用户的用户标识。

`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. Command Line Interface

版本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. Command line options

`-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. Examples

如何将整个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()`中的过滤器参数创建归档并重置用户信息：

    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. Supported tar formats

有三种tar格式可以使用`tarfile`模块创建：

- 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 issues

tar格式最初是为了在磁带驱动器上进行备份，主要侧重于保留文件系统信息。现在tar存档通常用于文件分发和通过网络交换档案。原始格式（这是所有其他格式的基础）的一个问题是没有支持不同字符编码的概念。例如，如果Latin-1系统中包含非ASCII，则在UTF-8系统上创建的普通tar存档无法正确读取>字符。文本元数据（如文件名，链接名，用户/组名称）将显示已损坏。不幸的是，没有办法自动检测归档的编码。pax格式被设计来解决这个问题。它使用通用字符编码UTF-8存储非ASCII元数据。

`tarfile`中的字符转换详细信息由`TarFile`类的编码和错误关键字参数控制。

encoding定义要用于存档中元数据的字符编码。默认值为`sys.getfilesystemencoding()`或`'ascii'`作为后备。根据归档是读还是写，元数据必须解码或编码。如果未正确设置编码，则此转换可能会失败。

errors参数定义如何处理无法转换的字符。可能的值在Error Handlers部分中列出。默认方案是Python还用于其文件系统调用的`'surrogateescape'`，请参阅File Names, Command Line Arguments, and Environment Variables。

在`PAX_FORMAT`档案的情况下，通常不需要编码，因为所有元数据都使用UTF-8存储。encoding is only used in the rare cases when binary pax headers are decoded or when strings with surrogate characters are stored.