"shutil" --- 高层级文件操作
***************************

**源代码：** Lib/shutil.py

======================================================================

"shutil" 模块提供了一系列对文件和文件集合的高阶操作。 特别是提供了一些
支持文件拷贝和删除的函数。 对于单个文件的操作，请参阅 "os" 模块。

警告:

  即便是高阶文件拷贝函数 ("shutil.copy()", "shutil.copy2()") 也无法拷
  贝所有的文件元数据。在 POSIX 平台上，这意味着将丢失文件所有者和组以
  及 ACL 数据。 在 Mac OS 上，资源钩子和其他元数据不被使用。 这意味着
  将丢失这些资源并且文件类型和创建者代码将不正确。 在 Windows 上，将不
  会拷贝文件所有者、ACL 和替代数据流。


目录和文件操作
==============

shutil.copyfileobj(fsrc, fdst[, length])

   将 *文件型对象* *fsrc* 的内容拷贝到文件型对象 *fdst*。 如果给出了整
   数值 *length*，即为缓冲区大小。 特别地，*length* 为负值表示拷贝数据
   时不对源数据进行分块循环处理；在默认情况下会分块读取数据以避免不受
   控制的内存消耗。 请注意如果 *fsrc* 对象的当前文件位置不为 0，只有从
   当前文件位置到文件末尾的内容会被拷贝。

   "copyfileobj()" 将 *不* 保证目标流在拷贝完成时已被刷新。 如果你希望
   在复制操作完成时从目标文件读取（例如，读取从HTTP流复制的临时文件的
   内容），则必须确保在尝试读取目标文件之前在文件型对象上调用了
   "flush()" 或 "close()"。

shutil.copyfile(src, dst, *, follow_symlinks=True)

   将名为 *src* 的文件的内容（不带元数据）拷贝到名为 *dst* 的文件并以
   尽可能高效的方式返回 *dst*。 *src* 和 *dst* 均为 *数据型对象* 或字
   符串形式的路径名。

   *dst* 必须是完整的目标文件名；对于接受目标目录路径的拷贝请参见
   "copy()"。 如果 *src* 和 *dst* 指定了同一个文件，则将引发
   "SameFileError"。

   目标位置必须是可写的；否则将引发 "OSError" 异常。 如果 *dst* 已经存
   在，它将被替换。 特殊文件如字符或块设备以及管道无法用此函数来拷贝。

   如果 *follow_symlinks* 为假值且 *src* 为符号链接，则将创建一个新的
   符号链接而不是拷贝 *src* 所指向的文件。

   引发一个 审计事件 "shutil.copyfile" 并附带参数 "src", "dst"。

   在 3.3 版本发生变更: 曾经是引发 "IOError" 而不是 "OSError"。 增加了
   *follow_symlinks* 参数。 现在是返回 *dst*。

   在 3.4 版本发生变更: 引发 "SameFileError" 而不是 "Error"。 由于前者
   是后者的子类，此改变是向后兼容的。

   在 3.8 版本发生变更: 可能会在内部使用平台专属的快速拷贝系统调用以更
   高效地拷贝文件。 参见 依赖于具体平台的高效拷贝操作 一节。

exception shutil.SpecialFileError

   此异常会在 "copyfile()" 或 "copytree()" 试图拷贝命名管道时被引发。

   Added in version 2.7.

exception shutil.SameFileError

   此异常会在 "copyfile()" 中的源和目标为同一文件时被引发。

   Added in version 3.4.

shutil.copymode(src, dst, *, follow_symlinks=True)

   将权限位从 *src* 拷贝到 *dst*。 文件的内容、所有者和分组将不受影响
   。 *src* 和 *dst* 均为 *路径型对象* 或字符串形式的路径名。 如果
   *follow_symlinks* 为假值，并且 *src* 和 *dst* 均为符号链接，则
   "copymode()" 将尝试修改 *dst* 本身的模式（而不是它所指向的文件）。
   此功能并不是在所有平台上均可用；请参阅 "copystat()" 了解详情。 如果
   "copymode()" 无法修改本机平台上的符号链接，而它被要求这样做，它将不
   做任何操作即返回。

   引发一个 审计事件 "shutil.copymode" 并附带参数 "src", "dst"。

   在 3.3 版本发生变更: 加入 *follow_symlinks* 参数。

shutil.copystat(src, dst, *, follow_symlinks=True)

   将权限位、最近访问时间、最近修改时间和旗标从 *src* 拷贝到 *dst*。
   在 Linux 上，"copystat()" 还会在可能的情况下拷贝“扩展属性”。 文件的
   内容、所有者和分组将不受影响。 *src* 和 *dst* 均为 *路径型对象* 或
   字符串形式的路径名。

   如果 *follow_symlinks* 为假值，并且 *src* 和 *dst* 均指向符号链接，
   "copystat()" 将作用于符号链接本身而非该符号链接所指向的文件 — 从
   *src* 符号链接读取信息，并将信息写入 *dst* 符号链接。

   备注:

     并非所有平台者提供检查和修改符号链接的功能。 Python 本身可以告诉
     你哪些功能是在本机上可用的。

     * 如果 "os.chmod in os.supports_follow_symlinks" 为 "True"，则
       "copystat()" 可以修改符号链接的权限位。

     * 如果 "os.utime in os.supports_follow_symlinks" 为 "True"，则
       "copystat()" 可以修改符号链接的最近访问和修改时间。

     * 如果 "os.chflags in os.supports_follow_symlinks" 为 "True"，则
       "copystat()" 可以修改符号链接的旗标。 ("os.chflags" 不是在所有
       平台上均可用。)

     在此功能部分或全部不可用的平台上，当被要求修改一个符号链接时，
     "copystat()" 将尽量拷贝所有内容。 "copystat()" 一定不会返回失败信
     息。更多信息请参阅 "os.supports_follow_symlinks"。

   引发一个 审计事件 "shutil.copystat" 并附带参数 "src", "dst"。

   在 3.3 版本发生变更: 添加了 *follow_symlinks* 参数并且支持 Linux 扩
   展属性。

shutil.copy(src, dst, *, follow_symlinks=True)

   将文件 *src* 拷贝到文件或目录 *dst*。 *src* 和 *dst* 应为 *路径类对
   象* 或字符串。 如果 *dst* 指定了一个目录，文件将使用 *src* 中的基准
   文件名拷贝到 *dst* 中。  如果 *dst* 指定了一个已存在的文件，它将被
   替换。 返回新创建文件所对应的路径。

   如果 *follow_symlinks* 为假值且 *src* 为符号链接，则 *dst* 也将被创
   建为符号链接。 如果 *follow_symlinks* 为真值且 *src* 为符号链接，
   *dst* 将成为 *src* 所指向的文件的一个副本。

   "copy()" 会拷贝文件数据和文件的权限模式 (参见 "os.chmod()")。 其他
   元数据，例如文件的创建和修改时间不会被保留。 要保留所有原有的元数据
   ，请改用 "copy2()" 。

   引发一个 审计事件 "shutil.copyfile" 并附带参数 "src", "dst"。

   引发一个 审计事件 "shutil.copymode" 并附带参数 "src", "dst"。

   在 3.3 版本发生变更: 添加了 *follow_symlinks* 参数。 现在会返回新创
   建文件的路径。

   在 3.8 版本发生变更: 可能会在内部使用平台专属的快速拷贝系统调用以更
   高效地拷贝文件。 参见 依赖于具体平台的高效拷贝操作 一节。

shutil.copy2(src, dst, *, follow_symlinks=True)

   类似于 "copy()"，区别在于 "copy2()" 还会尝试保留文件的元数据。

   当 *follow_symlinks* 为假值，并且 *src* 为符号链接时，"copy2()" 会
   尝试将来自 *src* 符号链接的所有元数据拷贝到新创建的 *dst* 符号链接
   。 但是，此功能不是在所有平台上均可用。 在此功能部分或全部不可用的
   平台上，"copy2()" 将尽量保留所有元数据，"copy2()" 一定不会由于无法
   保留文件元数据而引发异常。

   "copy2()" 会使用 "copystat()" 来拷贝文件元数据。 请参阅
   "copystat()" 了解有关修改符号链接元数据的平台支持的更多信息。

   引发一个 审计事件 "shutil.copyfile" 并附带参数 "src", "dst"。

   引发一个 审计事件 "shutil.copystat" 并附带参数 "src", "dst"。

   在 3.3 版本发生变更: 添加了 *follow_symlinks* 参数，还会尝试拷贝扩
   展文件系统属性（目前仅限 Linux）。 现在会返回新创建文件的路径。

   在 3.8 版本发生变更: 可能会在内部使用平台专属的快速拷贝系统调用以更
   高效地拷贝文件。 参见 依赖于具体平台的高效拷贝操作 一节。

shutil.ignore_patterns(*patterns)

   这个工厂函数会创建一个函数，它可被用作 "copytree()" 的 *ignore* 可
   调用对象参数，以忽略那些匹配所提供的 glob 风格的 *patterns* 之一的
   文件和目录。 参见以下示例。

shutil.copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2, ignore_dangling_symlinks=False, dirs_exist_ok=False)

   递归地将以 *src* 为根起点的整个目录树拷贝到名为 *dst* 的目录并返回
   目标目录。 所需的包含 *dst* 的中间目录在默认情况下也将被创建。

   目录的权限和时间会通过 "copystat()" 来拷贝，单个文件则会使用
   "copy2()" 来拷贝。

   如果 *symlinks* 为真值，源目录树中的符号链接会在新目录树中表示为符
   号链接，并且原链接的元数据在平台允许的情况下也会被拷贝；如果为假值
   或省略，则会将被链接文件的内容和元数据拷贝到新目录树。

   当 *symlinks* 为假值时，如果符号链接所指向的文件不存在，则会在拷贝
   进程的末尾将一个异常添加到 "Error" 异常中的被引发错误列表。 如果你
   希望屏蔽此异常则可以将可选的 *ignore_dangling_symlinks* 旗标设为真
   值。 请注意此选项在不支持 "os.symlink()" 的平台上将不起作用。

   如果给出了 *ignore*，它必须是一个可调用对象，该对象将接受
   "copytree()" 所访问的目录以及 "os.listdir()" 所返回的目录内容列表作
   为其参数。 由于 "copytree()" 是递归地被调用的，*ignore* 可调用对象
   对于每个被拷贝目录都将被调用一次。 该可调用对象必须返回一个相对于当
   前目录的目录和文件名序列（即其第二个参数的子集）；随后这些名称将在
   拷贝进程中被忽略。 "ignore_patterns()" 可被用于创建这种基于 glob 风
   格模式来忽略特定名称的可调用对象。

   如果发生了（一个或多个）异常，将引发一个附带原因列表的 "Error"。

   如果给出了 *copy_function*，它必须是一个将被用来拷贝每个文件的可调
   用对象。 它在被调用时会将源路径和目标路径作为参数传入。 默认情况下
   ，"copy2()" 将被使用，但任何支持同样签名（与 "copy()" 一致）都可以
   使用。

   如果 *dirs_exist_ok* 为（默认的）假值且 *dst* 已存在，则会引发
   "FileExistsError"。 如果 *dirs_exist_ok* 为真值，则如果拷贝操作遇到
   已存在的目录时将继续执行，并且在 *dst* 目录树中的文件将被 *src* 目
   录树中对应的文件所覆盖。

   引发一个 审计事件 "shutil.copytree" 并附带参数 "src", "dst"。

   在 3.2 版本发生变更: 添加了 *copy_function* 参数以允许提供定制的拷
   贝函数。 添加了 *ignore_dangling_symlinks* 参数以便在 *symlinks* 为
   假值时屏蔽目标不存在的符号链接。

   在 3.3 版本发生变更: 当 *symlinks* 为假值时拷贝元数据。 现在会返回
   *dst*。

   在 3.8 版本发生变更: 可能会在内部使用平台专属的快速拷贝系统调用以更
   高效地拷贝文件。 参见 依赖于具体平台的高效拷贝操作 一节。

   在 3.8 版本发生变更: 增加了 *dirs_exist_ok* 形参。

shutil.rmtree(path, ignore_errors=False, onerror=None, *, onexc=None, dir_fd=None)

   删除一个完整的目录树；*path* 必须指向一个目录（但不能是一个目录的符
   号链接）。 如果 *ignore_errors* 为真值，则删除失败导致的错误将被忽
   略；如果为假值或被省略，则此类错误将通过调用由 *onexc* 或 *onerror*
   所指定的处理器来处理，或者如果此参数被省略，异常将被传播给调用方。

   本函数支持 基于目录描述符的相对路径。

   备注:

     在支持必要的基于 fd 的函数的平台上，默认会使用 "rmtree()" 的可防
     御符号链接攻击的版本。 在其他平台上，"rmtree()" 较易遭受符号链接
     攻击：给定适当的时间和环境，攻击者可以操纵文件系统中的符号链接来
     删除他们在其他情况下无法访问的文件。 应用程序可以使用
     "rmtree.avoids_symlink_attacks" 函数属性来确定此类情况具体是哪一
     些。

   如果提供了 *onexc*，它必须为接受三个形参的可调用对象: *function*,
   *path* 和 *excinfo*。

   第一个形参 *function* 是引发异常的函数；它依赖于具体的平台和实现。
   第二个形参 *path* 将为传递给 *function* 的路径名称。 第三个形参
   *excinfo* 是被引发的异常。 由 *onexc* 所引发的异常将不会被捕获。

   已弃用的 *onerror* 与 *onexc* 类似，区别在于它接受的第三个形参是从
   "sys.exc_info()" 返回的元组。

   参见: rmtree 示例 是一个处理删除包含只读文件的目录树的示例。

   引发一个 审计事件 "shutil.rmtree" 并附带参数 "path", "dir_fd"。

   在 3.3 版本发生变更: 添加了一个防御符号链接攻击的版本，如果平台支持
   基于 fd 的函数就会被使用。

   在 3.8 版本发生变更: 在 Windows 上将不会再在移除连接之前删除目录连
   接中的内容。

   在 3.11 版本发生变更: 添加了 *dir_fd* 参数。

   在 3.12 版本发生变更: 增加了 *onexc* 形参，弃用了 *onerror*。

   在 3.13 版本发生变更: 现在 "rmtree()" 会忽略最高层级路径以外所有路
   径的 "FileNotFoundError" 异常。 "OSError" 和 "OSError" 的子类现在总
   是会被传播给调用方。

   rmtree.avoids_symlink_attacks

      指明当前平台和实现是否提供防御符号链接攻击的 "rmtree()" 版本。
      目前它仅在平台支持基于 fd 的目录访问函数时才返回真值。

      Added in version 3.3.

shutil.move(src, dst, copy_function=copy2)

   递归地将一个文件或目录 (*src*) 移到另一位置并返回目标位置。

   如果 *dst* 为已存在的目录或指向目录的符号链接，则 *src* 将被移到该
   目录中。 目标路径在该目录中不能已存在。

   如果 *dst* 已存在但不是一个目录，则它可能会被覆盖，具体取决于
   "os.rename()" 的语义。

   如果目标是在当前文件系统中，则会使用 "os.rename()"。 在其他情况下，
   则使用 *copy_function* 将 *src* 拷贝至目标然后移除它。 对于符号链接
   ，则将创建一个指向 *src* 目标的新符号链接作为目标位置而 *src* 将被
   移除。

   如果给出了 *copy_function*，则它必须为接受两个参数 *src* 和目标位置
   的可调用对象，并将在 "os.rename()" 无法使用时被用来将 *src* 拷贝到
   目标位置。 如果源是一个目录，则会调用 "copytree()"，并向它传入
   *copy_function*。 默认的 *copy_function* 是 "copy2()"。 使用
   "copy()" 作为 *copy_function* 将允许在无法附带拷贝元数据时让移动操
   作成功执行，但其代价是不拷贝任何元数据。

   引发一个 审计事件 "shutil.move" 并附带参数 "src", "dst"。

   在 3.3 版本发生变更: 为异类文件系统添加了显式的符号链接处理，以便使
   它适应 GNU 的 **mv** 的行为。 现在会返回 *dst*。

   在 3.5 版本发生变更: 增加了 *copy_function* 关键字参数。

   在 3.8 版本发生变更: 可能会在内部使用平台专属的快速拷贝系统调用以更
   高效地拷贝文件。 参见 依赖于具体平台的高效拷贝操作 一节。

   在 3.9 版本发生变更: 接受一个 *path-like object* 作为 *src* 和
   *dst*。

shutil.disk_usage(path)

   返回给定路径的磁盘使用统计数据，形式为一个 *named tuple*，其中包含
   *total*, *used* 和 *free* 属性，分别表示总计、已使用和未使用空间的
   字节数。 *path* 可以是一个文件或是一个目录。

   备注:

     在 Unix 文件系统中，*path* 必须指向一个 **已挂载** 文件系统分区中
     的路径。 在这些平台上，CPython 不会尝试从未挂载的文件系统中获取磁
     盘使用信息。

   Added in version 3.3.

   在 3.8 版本发生变更: 在 Windows 上，*path* 现在可以是一个文件或目录
   。

   Availability: Unix, Windows.

shutil.chown(path, user=None, group=None, *, dir_fd=None, follow_symlinks=True)

   修改给定 *path* 的所有者 *user* 和/或 *group*。

   *user* 可以是一个系统用户名或 uid；*group* 同样如此。 要求至少有一
   个参数。

   另请参阅下层的函数 "os.chown()"。

   引发一个 审计事件 "shutil.chown" 并附带参数 "path", "user", "group"
   。

   Availability: Unix.

   Added in version 3.3.

   在 3.13 版本发生变更: 增加了 *dir_fd* 和 *follow_symlinks* 形参。

shutil.which(cmd, mode=os.F_OK | os.X_OK, path=None)

   返回当给定的 *cmd* 被调用时将要运行的可执行文件的路径。 如果没有
   *cmd* 会被调用则返回 "None"。

   *mode* 是一个传递给 "os.access()" 的权限掩码，在默认情况下将确定文
   件是否存在并且为可执行文件。

   *path* 是一个指明要查找的目录的 ""PATH" 字符串"，由 "os.pathsep" 分
   隔。 当未指定 *path* 时，将从 "os.environ" 读取 "PATH" 环境变量，如
   果其未被设置则将回退至 "os.defpath"。

   如果 *cmd* 包含目录部分，则 "which()" 仅直接检查指定的路径而不搜索
   在 *path* 或系统 "PATH" 环境变量中列出的目录。

   在 Windows 上，如果 *mode* 不包括 "os.X_OK" 则会将当前目录添加到
   *path* 中。 当 *mode* 包括 "os.X_OK" 时，则将通过 Windows API
   "NeedCurrentDirectoryForExePathW" 来确定当前目录是否应当添加到
   *path* 中。 要避免在当前工作目录下查找可执行文件：可设置
   "NoDefaultCurrentDirectoryInExePath" 环境变量。

   在 Windows 上，还会使用 "PATHEXT" 环境变量来处理可能尚未包括某个扩
   展的命令。 举例来说，如果你调用 "shutil.which("python")"，"which()"
   将搜索 "PATHEXT" 以获知应当在 *path* 的目录中查找 "python.exe"。 例
   如，在 Windows 上:

      >>> shutil.which("python")
      'C:\\Python33\\python.EXE'

   这也适用于当 *cmd* 是一个包含目录组成部分路径的情况:

      >>> shutil.which("C:\\Python33\\python")
      'C:\\Python33\\python.EXE'

   Added in version 3.3.

   在 3.8 版本发生变更: 现在可以接受 "bytes" 类型。 如果 *cmd* 的类型
   为 "bytes"，结果的类型也将为 "bytes"。

   在 3.12 版本发生变更: 在 Windows 上，如果 *mode* 包括 "os.X_OK" 且
   WinAPI "NeedCurrentDirectoryForExePathW(cmd)" 为假值则不会再将当前
   目录添加到搜索路径中，否则即使当前目录已经在搜索路径中仍会再次添加
   它；现在 "PATHEXT" 即使当 *cmd* 包括目录组成部分或以 "PATHEXT" 中的
   扩展名结束时仍然会被使用；并且没有扩展名的文件名现在也能被找到。

exception shutil.Error

   此异常会收集在多文件操作期间所引发的异常。 对于 "copytree()"，此异
   常参数将是一个由三元组 (*srcname*, *dstname*, *exception*) 构成的列
   表。


依赖于具体平台的高效拷贝操作
----------------------------

从 Python 3.8 开始，所有涉及文件拷贝的函数 ("copyfile()", "copy()",
"copy2()", "copytree()" 以及 "move()") 将会使用平台专属的 "fast-copy"
系统调用以便更高效地拷贝文件 (参见 bpo-33671)。 "fast-copy" 意味着拷贝
操作将发生于内核之中，避免像在 ""outfd.write(infd.read())"" 中那样使用
Python 用户空间的缓冲区。

在 macOS 上将会使用 fcopyfile 来拷贝文件内容（不含元数据）。

在 Linux 上将会使用 "os.copy_file_range()" 或 "os.sendfile()"。

在 Solaris 上将使用 "os.sendfile()"。

在 Windows 上 "shutil.copyfile()" 将会使用更大的默认缓冲区（1 MiB 而非
64 KiB）并且会使用基于 "memoryview()" 的 "shutil.copyfileobj()" 变种形
式。

如果快速拷贝操作失败并且没有数据被写入目标文件，则 shutil 将在内部静默
地回退到使用效率较低的 "copyfileobj()" 函数。

在 3.8 版本发生变更.

在 3.14 版本发生变更: Solaris 现在将使用 "os.sendfile()"。

在 3.14 版本发生变更: 在受支持的 Linux 文件系统上可能通过
"os.copy_file_range()" 在内部使用写入时拷贝或服务端拷贝。


copytree 示例
-------------

一个使用 "ignore_patterns()" 辅助函数的例子:

   from shutil import copytree, ignore_patterns

   copytree(source, destination, ignore=ignore_patterns('*.pyc', 'tmp*'))

这将会拷贝除 ".pyc" 文件和以 "tmp" 打头的文件或目录以外的所有条目.

另一个使用 *ignore* 参数来添加记录调用的例子:

   from shutil import copytree
   import logging

   def _logpath(path, names):
       logging.info('Working in %s', path)
       return []   # nothing will be ignored

   copytree(source, destination, ignore=_logpath)


rmtree 示例
-----------

这个例子演示了如何在 Windows 上删除一个目录树，其中部分文件设置了只读
属性位。 它会使用 onexc 回调函数来清除只读属性并再次尝试删除。 任何后
续的失败都将被传播。

   import os, stat
   import shutil

   def remove_readonly(func, path, _):
       "Clear the readonly bit and reattempt the removal"
       os.chmod(path, stat.S_IWRITE)
       func(path)

   shutil.rmtree(directory, onexc=remove_readonly)


归档操作
========

Added in version 3.2.

在 3.5 版本发生变更: 添加了对 *xztar* 格式的支持。

本模块也提供了用于创建和读取压缩和归档文件的高层级工具。 它们依赖于
"zipfile" 和 "tarfile" 模块。

shutil.make_archive(base_name, format[, root_dir[, base_dir[, verbose[, dry_run[, owner[, group[, logger]]]]]]])

   创建一个归档文件（例如 zip 或 tar）并返回其名称。

   *base_name* 是要创建的文件的名称，包括路径，去除任何格式专属的扩展
   名。

   *format* 是归档格式：为 "zip" (如果 "zlib" 模块可用), "tar",
   "gztar" (如果 "zlib" 模块可用), "bztar" (如果 "bz2" 模块可用),
   "xztar" (如果 "lzma" 模块可用) 或 "zstdtar" (如果
   "compression.zstd" 模块可用) 中的一个。

   *root_dir* 是一个目录，它将作为归档文件的根目录，归档中的所有路径都
   将是它的相对路径；例如，我们通常会在创建归档之前用 chdir 命令切换到
   *root_dir*。

   *base_dir* 是我们要执行归档的起始目录；也就是说 *base_dir* 将成为归
   档中所有文件和目录共有的路径前缀。 *base_dir* 必须相对于 *root_dir*
   给出。 请参阅 使用 base_dir 的归档程序示例 了解如何同时使用
   *base_dir* 和 *root_dir*。

   *root_dir* 和 *base_dir* 默认均为当前目录。

   如果 *dry_run* 为真值，则不会创建归档文件，但将要被执行的操作会被记
   录到 *logger*。

   *owner* 和 *group* 将在创建 tar 归档文件时被使用。 默认会使用当前的
   所有者和分组。

   *logger* 必须是一个兼容 **PEP 282** 的对象，通常为 "logging.Logger"
   的实例。

   *verbose* 参数已不再使用并进入弃用状态。

   引发一个 审计事件 "shutil.make_archive" 并附带参数 "base_name",
   "format", "root_dir", "base_dir"。

   备注:

     此函数在通过 "register_archive_format()" 注册的自定义归档程序不支
     持 *root_dir* 参数时时不是线程安全的。 在这种情况下它会临时改变进
     程的当前工作目录到 *root_dir* 来执行归档操作。

   在 3.8 版本发生变更: 现在对于通过 "format="tar"" 创建的归档文件将使
   用新式的 pax (POSIX.1-2001) 格式而非旧式的 GNU 格式。

   在 3.10.6 版本发生变更: 目前此函数在创建标准 ".zip" 和 tar 归档文件
   期间会确保是线程安全的。

shutil.get_archive_formats()

   返回支持的归档格式列表。 所返回序列中的每个元素为一个元组 "(name,
   description)"。

   默认情况下 "shutil" 提供以下格式:

   * *zip*: ZIP 文件（如果 "zlib" 模块可用）。

   * *tar*: 未压缩的 tar 文件。 对于新归档文件将使用 POSIX.1-2001 pax
     格式。

   * *gztar*: gzip 压缩的 tar 文件（如果 "zlib" 模块可用）。

   * *bztar*: bzip2 压缩的 tar 文件（如果 "bz2" 模块可用）。

   * *xztar*: xz 压缩的 tar 文件（如果 "lzma" 模块可用）。

   * *zstdtar*: Zstandard 压缩的 tar 文件（如果 "compression.zstd" 模
     块可用）。

   你可以通过使用 "register_archive_format()" 注册新的格式或为任何现有
   格式提供你自己的归档器。

shutil.register_archive_format(name, function[, extra_args[, description]])

   为 *name* 格式注册一个归档器。

   *function* 是将被用来解包归档文件的可调用对象。 该可调用对象将接收
   要创建文件的 *base_name*，再加上要归档内容的 *base_dir* (其默认值为
   "os.curdir")。 更多参数会被作为关键字参数传入: *owner*, *group*,
   *dry_run* 和 *logger* (与向 "make_archive()" 传入的参数一致)。

   如果 *function* 将自定义属性 "function.supports_root_dir" 设为
   "True"，则会以关键字参数形式传递 *root_dir* 参数。 否则进程的当前工
   作目录将在调用 *function* 之前被临时更改为 *root_dir*。 在此情况下
   "make_archive()" 将不是线程安全的。

   如果给出了 *extra_args*，则其应为一个 "(name, value)" 对的序列，将
   在归档器可调用对象被使用时作为附加的关键字参数。

   *description* 由 "get_archive_formats()" 使用，它将返回归档器的列表
   。 默认值为一个空字符串。

   在 3.12 版本发生变更: 增加了对支持 *root_dir* 参数的函数的支持。

shutil.unregister_archive_format(name)

   从支持的格式中移除归档格式 *name*。

shutil.unpack_archive(filename[, extract_dir[, format[, filter]]])

   解包一个归档文件。 *filename* 是归档文件的完整路径。

   *extract_dir* 是归档文件解包的目标目录名称。 如果未提供，则将使用当
   前工作目录。

   *format* 是归档格式：应为 "zip", "tar", "gztar", "bztar", "xztar"
   或 "zstdtar" 中的一个。 或者任何通过 "register_unpack_format()" 注
   册的其他格式。 如果未提供，则 "unpack_archive()" 将使用归档文件的扩
   展名来检查是否注册了对应于该扩展名的解包器。 对于未找到任何解包器的
   情况，将引发 "ValueError"。

   仅限关键字参数 *filter* 将被传给下层的解包函数。 对于 zip 文件，
   *filter* 将不被接受。 对于 tar 文件，推荐使用 "'data'" (自 Python
   3.14 起为默认值)，除非使用了 tar 和 UNIX 类文件系统专属的特性。 （
   请参阅 解压缩过滤器 了解详情。）

   引发一个 审计事件 "shutil.unpack_archive" 并附带参数 "filename",
   "extract_dir", "format"。

   警告:

     绝不要未经预先检验就从不可靠的源中提取归档文件。 这样有可能会在
     *extract_dir* 参数所指定的路径之外创建文件，例如某些成员具有以
     "/" 打头的绝对路径文件名或是以两个点号 ".." 打头的文件名。自
     Python 3.14 起，两种内置格式（zip 和 tar 文件）的默认设置将能防止
     最危险的此类安全问题，但是不能防止 *所有* 非故意的行为。 请参阅
     进一步核验的提示 一节了解 tar 专属的细节。

   在 3.7 版本发生变更: 接受一个 *path-like object* 作为 *filename* 和
   *extract_dir*。

   在 3.12 版本发生变更: 增加了 *filter* 参数。

shutil.register_unpack_format(name, extensions, function[, extra_args[, description]])

   注册一个解包格式。 *name* 为格式名称而 *extensions* 为对应于该格式
   的扩展名列表，例如 Zip 文件的扩展名为 ".zip"。

   *function* 是将被用于解包归档的可调用对象。 该可调用对象将接受:

   * 归档的路径，为位置参数;

   * 归档要提取到的目录，为位置参数;

   * 可选的 *filter* 关键字参数，如果有提供给 "unpack_archive()" 的话;

   * 额外的关键字参数，由 "(name, value)" 元组组成的序列 *extra_args*
     指明。

   可以提供 *description* 来描述该格式，它将被 "get_unpack_formats()"
   返回。

shutil.unregister_unpack_format(name)

   撤销注册一个解包格式。 *name* 为格式的名称。

shutil.get_unpack_formats()

   返回所有已注册的解包格式列表。 所返回序列中的每个元素为一个元组
   "(name, extensions, description)"。

   默认情况下 "shutil" 提供以下格式:

   * *zip*: ZIP 文件（只有在相应模块可用时才能解包压缩文件）。

   * *tar*: 未压缩的 tar 文件。

   * *gztar*: gzip 压缩的 tar 文件（如果 "zlib" 模块可用）。

   * *bztar*: bzip2 压缩的 tar 文件（如果 "bz2" 模块可用）。

   * *xztar*: xz 压缩的 tar 文件（如果 "lzma" 模块可用）。

   * *zstdtar*: Zstandard 压缩的 tar 文件（如果 "compression.zstd" 模
     块可用）。

   你可以通过使用 "register_unpack_format()" 注册新的格式或为任何现有
   格式提供你自己的解包器。


归档程序示例
------------

在这个示例中，我们创建了一个 gzip 压缩的 tar 归档文件，其中包含用户的
".ssh" 目录下的所有文件:

   >>> from shutil import make_archive
   >>> import os
   >>> archive_name = os.path.expanduser(os.path.join('~', 'myarchive'))
   >>> root_dir = os.path.expanduser(os.path.join('~', '.ssh'))
   >>> make_archive(archive_name, 'gztar', root_dir)
   '/Users/tarek/myarchive.tar.gz'

结果归档文件中包含有:

   $ tar -tzvf /Users/tarek/myarchive.tar.gz
   drwx------ tarek/staff       0 2010-02-01 16:23:40 ./
   -rw-r--r-- tarek/staff     609 2008-06-09 13:26:54 ./authorized_keys
   -rwxr-xr-x tarek/staff      65 2008-06-09 13:26:54 ./config
   -rwx------ tarek/staff     668 2008-06-09 13:26:54 ./id_dsa
   -rwxr-xr-x tarek/staff     609 2008-06-09 13:26:54 ./id_dsa.pub
   -rw------- tarek/staff    1675 2008-06-09 13:26:54 ./id_rsa
   -rw-r--r-- tarek/staff     397 2008-06-09 13:26:54 ./id_rsa.pub
   -rw-r--r-- tarek/staff   37192 2010-02-06 18:23:10 ./known_hosts


使用 *base_dir* 的归档程序示例
------------------------------

在这个例子中，与 上面的例子 类似，我们演示了如何使用 "make_archive()"
，但这次是使用 *base_dir*。 我们现在具有如下的目录结构:

   $ tree tmp
   tmp
   └── root
       └── structure
           ├── content
               └── please_add.txt
           └── do_not_add.txt

在最终的归档中，应当会包括 "please_add.txt"，但不应当包括
"do_not_add.txt"。 因此我们使用以下代码:

   >>> from shutil import make_archive
   >>> import os
   >>> archive_name = os.path.expanduser(os.path.join('~', 'myarchive'))
   >>> make_archive(
   ...     archive_name,
   ...     'tar',
   ...     root_dir='tmp/root',
   ...     base_dir='structure/content',
   ... )
   '/Users/tarek/myarchive.tar'

列出结果归档中的文件我们将会得到:

   $ python -m tarfile -l /Users/tarek/myarchive.tar
   structure/content/
   structure/content/please_add.txt


查询输出终端的尺寸
==================

shutil.get_terminal_size(fallback=(columns, lines))

   获取终端窗口的尺寸。

   对于两个维度中的每一个，会分别检查环境变量 "COLUMNS" 和 "LINES"。
   如果定义了这些变量并且其值为正整数，则将使用这些值。

   如果未定义 "COLUMNS" 或 "LINES"，这是通常的情况，则连接到
   "sys.__stdout__" 的终端将通过唤起 "os.get_terminal_size()" 被查询。

   如果由于系统不支持查询，或是由于我们未连接到某个终端而导致查询终端
   尺寸不成功，则会使用在 "fallback" 形参中给出的值。 "fallback" 默认
   为 "(80, 24)"，这是许多终端模拟器所使用的默认尺寸。

   返回的值是一个 "os.terminal_size" 类型的具名元组。

   另请参阅: The Single UNIX Specification, Version 2, Other
   Environment Variables.

   Added in version 3.3.

   在 3.11 版本发生变更: 如果 "os.get_terminal_size()" 返回零值则
   "fallback" 值也将被使用。
