"zipfile" --- 使用ZIP存档
*************************

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

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

ZIP 文件格式是一个常用的归档与压缩标准。 这个模块提供了创建、读取、写
入、添加及列出 ZIP 文件的工具。 任何对此模块的进阶使用都将需要理解此格
式，其定义参见 PKZIP 应用程序笔记。

此模块目前不能处理分卷 ZIP 文件。它可以处理使用 ZIP64 扩展（超过 4 GB
的 ZIP 文件）的 ZIP 文件。它支持解密 ZIP 归档中的加密文件，但是目前不
能创建一个加密的文件。解密非常慢，因为它是使用原生 Python 而不是 C 实
现的。

这个模块定义了以下内容：

exception zipfile.BadZipFile

   为损坏的 ZIP 文件抛出的错误。

   3.2 版新加入.

exception zipfile.BadZipfile

   "BadZipFile" 的别名，与旧版本 Python 保持兼容性。

   3.2 版後已棄用.

exception zipfile.LargeZipFile

   当 ZIP 文件需要 ZIP64 功能但是未启用时会抛出此错误。

class zipfile.ZipFile

   用于读写 ZIP 文件的类。 欲了解构造函数的描述，参阅段落 ZipFile 对象
   。

class zipfile.Path

   用于 zip 文件的兼容 pathlib 的包装器。 详情参见 Path 对象。

   3.8 版新加入.

class zipfile.PyZipFile

   用于创建包含 Python 库的 ZIP 归档的类。

class zipfile.ZipInfo(filename='NoName', date_time=(1980, 1, 1, 0, 0, 0))

   用于表示档案内一个成员信息的类。 此类的实例会由 "ZipFile" 对象的
   "getinfo()" 和 "infolist()" 方法返回。 大多数 "zipfile" 模块的用户
   都不必创建它们，只需使用此模块所创建的实例。 *filename* 应当是档案
   成员的全名，*date_time* 应当是包含六个字段的描述最近修改时间的元组
   ；这些字段的描述请参阅 ZipInfo 对象。

zipfile.is_zipfile(filename)

   根据文件的 Magic Number，如果 *filename* 是一个有效的 ZIP 文件则返
   回 "True"，否则返回 "False"。 *filename* 也可能是一个文件或类文件对
   象。

   3.1 版更變: 支持文件或类文件对象。

zipfile.ZIP_STORED

   未被压缩的归档成员的数字常数。

zipfile.ZIP_DEFLATED

   常用的 ZIP 压缩方法的数字常数。需要 "zlib" 模块。

zipfile.ZIP_BZIP2

   BZIP2 压缩方法的数字常数。需要 "bz2" 模块。

   3.3 版新加入.

zipfile.ZIP_LZMA

   LZMA 压缩方法的数字常数。需要 "lzma" 模块。

   3.3 版新加入.

   備註:

     ZIP 文件格式规范包括自 2001 年以来对 bzip2 压缩的支持，以及自
     2006 年以来对 LZMA 压缩的支持。但是，一些工具（包括较旧的 Python
     版本）不支持这些压缩方法，并且可能拒绝完全处理 ZIP 文件，或者无法
     提取单个文件。

也參考:

  PKZIP 应用程序笔记
     Phil Katz 编写的 ZIP 文件格式文档，此格式和使用的算法的创建者。

  Info-ZIP 主页
     有关 Info-ZIP 项目的 ZIP 存档程序和开发库的信息。


ZipFile 对象
============

class zipfile.ZipFile(file, mode='r', compression=ZIP_STORED, allowZip64=True, compresslevel=None, *, strict_timestamps=True)

   打开一个 ZIP 文件，*file* 为一个指向文件的路径（字符串），一个类文
   件对象或者一个 *path-like object*。

   形参 *mode* 应当为 "'r'" 来读取一个存在的文件，"'w'" 来截断并写入新
   的文件， "'a'" 来添加到一个存在的文件，或者 "'x'" 来仅新建并写入新
   的文件。如果 *mode* 为 "'x'" 并且 *file* 指向已经存在的文件，则抛出
   "FileExistsError"。如果 *mode* 为 "'a'" 且 *file* 为已存在的文件，
   则格外的文件将被加入。如果 *file* 不指向 ZIP 文件，之后一个新的 ZIP
   归档将被追加为此文件。这是为了将 ZIP 归档添加到另一个文件（例如
   "python.exe"）。如果 *mode* 为 "'a'" 并且文件不存在， 则会新建。如
   果 *mode* 为 "'r'" 或 "'a'"， 则文件应当可定位。

   *compression* 是在写入归档时要使用的 ZIP 压缩方法，应为
   "ZIP_STORED", "ZIP_DEFLATED", "ZIP_BZIP2" 或 "ZIP_LZMA"；不可识别的
   值将导致引发 "NotImplementedError"。 如果指定了 "ZIP_DEFLATED",
   "ZIP_BZIP2" 或 "ZIP_LZMA" 但相应的模块 ("zlib", "bz2" 或 "lzma") 不
   可用，则会引发 "RuntimeError"。 默认值为 "ZIP_STORED"。

   如果 *allowZip64* 为 "True" (默认值) 则当 zipfile 大于 4 GiB 时
   zipfile 将创建使用 ZIP64 扩展的 ZIP 文件。 如果该参数为 "false" 则
   当 ZIP 文件需要 ZIP64 扩展时 "zipfile" 将引发异常。

   *compresslevel* 形参控制在将文件写入归档时要使用的压缩等级。 当使用
   "ZIP_STORED" 或 "ZIP_LZMA" 时无压缩效果。 当使用 "ZIP_DEFLATED" 时
   接受整数 "0" 至 "9" (更多信息参见 "zlib")。 当使用 "ZIP_BZIP2" 时接
   受整数 "1" 至 "9" (更多信息参见 "bz2")。

   *strict_timestamps* 参数在设为 "False" 时允许压缩早于 1980-01-01 的
   文件，代价时会将时间戳设为 1980-01-01。 类似的行为也会对晚于
   2107-12-31 的文件发生，时间戳也会被设为该上限值。

   如果创建文件时使用 "'w'", "'x'" 或 "'a'" 模式并且未向归档添加任何文
   件就执行了 "closed"，则会将适当的空归档 ZIP 结构写入文件。

   ZipFile 也是一个上下文管理器，因此支持 "with" 语句。 在这个示例中，
   *myzip* 将在 "with" 语句块执行完成之后被关闭 --- 即使是发生了异常:

      with ZipFile('spam.zip', 'w') as myzip:
          myzip.write('eggs.txt')

   3.2 版新加入: 添加了将 "ZipFile" 用作上下文管理员的功能。

   3.3 版更變: 添加了对 "bzip2" 和 "lzma" 压缩的支持。

   3.4 版更變: 默认启用 ZIP64 扩展。

   3.5 版更變: 添加了对不可查找数据流的支持。 并添加了对 "'x'" 模式的
   支持。

   3.6 版更變: 在此之前，对于不可识别的压缩值将引发普通的
   "RuntimeError"。

   3.6.2 版更變: *file* 形参接受一个 *path-like object*。

   3.7 版更變: 添加了 *compresslevel* 形参。

   3.8 版新加入: *strict_timestamps* 仅限关键字参数

ZipFile.close()

   关闭归档文件。 你必须在退出程序之前调用 "close()" 否则将不会写入关
   键记录数据。

ZipFile.getinfo(name)

   返回一个 "ZipInfo" 对象，其中包含有关归档成员 *name* 的信息。 针对
   一个目前并不包含于归档中的名称调用 "getinfo()" 将会引发 "KeyError"
   。

ZipFile.infolist()

   返回一个列表，其中包含每个归档成员的 "ZipInfo" 对象。 如果是打开一
   个现有归档则这些对象的排列顺序与它们对应条目在磁盘上的实际 ZIP 文件
   中的顺序一致。

ZipFile.namelist()

   返回按名称排序的归档成员列表。

ZipFile.open(name, mode='r', pwd=None, *, force_zip64=False)

   以二进制文件类对象的形式访问一个归档成员。 *name* 可以是归档内某个
   文件的名称也可以是某个 "ZipInfo" 对象。 如果包含了 *mode* 形参，则
   它必须为 "'r'" (默认值) 或 "'w'"。  *pwd* 为用于解密已加密 ZIP 文件
   的密码。

   "open()" 也是一个上下文管理器，因此支持 "with" 语句:

      with ZipFile('spam.zip') as myzip:
          with myzip.open('eggs.txt') as myfile:
              print(myfile.read())

   如果 *mode* 为 "'r'" 则文件类对象 ("ZipExtFile") 将为只读并且提供下
   列方法: "read()", "readline()", "readlines()", "seek()", "tell()",
   "__iter__()", "__next__()"。 这些对象可独立于 ZipFile 进行操作。

   如果 "mode='w'" 则返回一个可写入的文件句柄，它将支持 "write()" 方法
   。 当一个可写入的文件句柄被打开时，尝试读写 ZIP 文件中的其他文件将
   会引发 "ValueError"。

   当写入一个文件时，如果文件大小不能预先确定但是可能超过 2 GiB，可传
   入 "force_zip64=True" 以确保标头格式能够支持超大文件。 如果文件大小
   可以预先确定，则在构造 "ZipInfo" 对象时应设置 "file_size"，并将其用
   作 *name* 形参。

   備註:

     "open()", "read()" 和 "extract()" 方法可接受文件名或 "ZipInfo" 对
     象。 当尝试读取一个包含重复名称成员的 ZIP 文件时你将发现此功能很
     有好处。

   3.6 版更變: 移除了对 "mode='U'" 的支持。 请使用 "io.TextIOWrapper"
   以在 *universal newlines* 模式中读取已压缩的文本文件。

   3.6 版更變: "open()" 现在可以被用来配合 "mode='w'" 选项来将文件写入
   归档。

   3.6 版更變: 在已关闭的 ZipFile 上调用 "open()" 将引发 "ValueError"
   。 在之前的版本中则会引发 "RuntimeError"。

ZipFile.extract(member, path=None, pwd=None)

   从归档中提取出一个成员放入当前工作目录；*member* 必须为成员的完整名
   称或 "ZipInfo" 对象。 成员的文件信息会尽可能精确地被提取。 *path*
   指定一个要提取到的不同目录。 *member* 可以是一个文件名或 "ZipInfo"
   对象。 *pwd* 是用于解密文件的密码。

   返回所创建的经正规化的路径（对应于目录或新文件）。

   備註:

     如果一个成员文件名为绝对路径，则将去掉驱动器/UNC共享点和前导的（
     反）斜杠，例如: "///foo/bar" 在 Unix 上将变为 "foo/bar"，而
     "C:\foo\bar" 在 Windows 上将变为 "foo\bar"。 并且一个成员文件名中
     的所有 "".."" 都将被移除，例如: "../../foo../../ba..r" 将变为
     "foo../ba..r"。 在 Windows 上非法字符 (":", "<", ">", "|", """,
     "?", and "*") 会被替换为下划线 ("_")。

   3.6 版更變: 在已关闭的 ZipFile 上调用 "extract()" 将引发
   "ValueError"。 在之前的版本中则将引发 "RuntimeError"。

   3.6.2 版更變: *path* 形参接受一个 *path-like object*。

ZipFile.extractall(path=None, members=None, pwd=None)

   从归档中提取出所有成员放入当前工作目录。 *path* 指定一个要提取到的
   不同目录。 *members* 为可选项且必须为 "namelist()" 所返回列表的一个
   子集。 *pwd* 是用于解密文件的密码。

   警告:

     绝不要未经预先检验就从不可靠的源中提取归档文件。 这样有可能在
     *path* 之外创建文件，例如某些成员具有以 ""/"" 开始的文件名或带有
     两个点号 "".."" 的文件名。 此模块会尝试防止这种情况。 参见
     "extract()" 的注释。

   3.6 版更變: 在已关闭的 ZipFile 上调用 "extractall()" 将引发
   "ValueError"。 在之前的版本中则将引发 "RuntimeError"。

   3.6.2 版更變: *path* 形参接受一个 *path-like object*。

ZipFile.printdir()

   将归档的目录表打印到 "sys.stdout"。

ZipFile.setpassword(pwd)

   设置 *pwd* 为用于提取已加密文件的默认密码。

ZipFile.read(name, pwd=None)

   返回归档中文件 *name* 的字节数据。 *name* 是归档中文件的名称，或是
   一个 "ZipInfo" 对象。 归档必须以读取或追加方式打开。 *pwd* 为用于已
   加密文件的密码，并且如果指定该参数则它将覆盖通过 "setpassword()" 设
   置的默认密码。  on a ZipFile that uses a compression method 在使用
   "ZIP_STORED" , "ZIP_DEFLATED", "ZIP_BZIP2" 或 "ZIP_LZMA" 以外的压缩
   方法的 ZipFile 上调用 "read()" 将引发 "NotImplementedError"。 如果
   相应的压缩模块不可用也会引发错误。

   3.6 版更變: 在已关闭的 ZipFile 上调用 "read()" 将引发 "ValueError"
   。 在之前的版本中则会引发 "RuntimeError"。

ZipFile.testzip()

   读取归档中的所有文件并检查它们的 CRC 和文件头。 返回第一个已损坏文
   件的名称，在其他情况下则返回 "None"。

   3.6 版更變: 在已关闭的 ZipFile 上调用 "testzip()" 将引发
   "ValueError"。 在之前的版本中则将引发 "RuntimeError"。

ZipFile.write(filename, arcname=None, compress_type=None, compresslevel=None)

   将名为 *filename* 的文件写入归档，给予的归档名为 *arcname* (默认情
   况下将与 *filename* 一致，但是不带驱动器盘符并会移除开头的路径分隔
   符)。 *compress_type* 如果给出，它将覆盖作为构造器 *compression* 形
   参对于新条目所给出的值。 类似地，*compresslevel* 如果给出也将覆盖构
   造器。 归档必须使用 "'w'", "'x'" 或 "'a'" 模式打开。

   備註:

     归档名称应当是基于归档根目录的相对路径，也就是说，它们不应以路径
     分隔符开头。

   備註:

     如果 "arcname" (或 "filename"，如果 "arcname" 未给出) 包含一个空
     字节，则归档中该文件的名称将在空字节位置被截断。

   3.6 版更變: 在使用 "'r'" 模式创建的 ZipFile 或已关闭的 ZipFile 上调
   用 "write()" 将引发 "ValueError"。 在之前的版本中则会引发
   "RuntimeError"。

ZipFile.writestr(zinfo_or_arcname, data, compress_type=None, compresslevel=None)

   将一个文件写入归档。 内容为 *data*，它可以是一个 "str" 或 "bytes"
   的实例；如果是 "str"，则会先使用 UTF-8 进行编码。
   *zinfo_or_arcname* 可以是它在归档中将被给予的名称，或者是 "ZipInfo"
   的实例。 如果它是一个实例，则至少必须给定文件名、日期和时间。 如果
   它是一个名称，则日期和时间会被设为当前日期和时间。 归档必须以
   "'w'", "'x'" 或 "'a'" 模式打开。

   如果给定了 *compress_type*，它将会覆盖作为新条目构造器的
   *compression* 形参或在 *zinfo_or_arcname* (如果是一个 "ZipInfo" 实
   例) 中所给出的值。 类似地，如果给定了 *compresslevel*，它将会覆盖构
   造器。

   備註:

     当传入一个 "ZipInfo" 实例作为 *zinfo_or_arcname* 形参时，所使用的
     压缩方法将为在给定的 "ZipInfo" 实例的 *compress_type* 成员中指定
     的方法。 默认情况下，"ZipInfo" 构造器将将此成员设为 "ZIP_STORED"
     。

   3.2 版更變: *compress_type* 参数。

   3.6 版更變: 在使用 "'r'" 模式创建的 ZipFile 或已关闭的 ZipFile 上调
   用 "writestr()" 将引发 "ValueError"。 在之前的版本中则会引发
   "RuntimeError"。

以下数据属性也是可用的:

ZipFile.filename

   ZIP 文件的名称。

ZipFile.debug

   要使用的调试输出等级。 这可以设为从 "0" (默认无输出) 到 "3" (最多输
   出) 的值。 调试信息会被写入 "sys.stdout"。

ZipFile.comment

   关联到 ZIP 文件的 "bytes" 对象形式的说明。 如果将说明赋给以 "'w'",
   "'x'" 或 "'a'" 模式创建的 "ZipFile" 实例，它的长度不应超过 65535 字
   节。 超过此长度的说明将被截断。


Path 对象
=========

class zipfile.Path(root, at='')

   根据 "root" zipfile (它可以是一个 "ZipFile" 实例或适合传给
   "ZipFile" 构造器的 "file") 构造一个 Path 对象。

   "at" 指定此 Path 在 zipfile 中的位置，例如 'dir/file.txt', 'dir/'
   或 ''。 默认为空字符串，即指定跟目录。

Path 对象会公开 "pathlib.Path" 对象的下列特性:

Path 对象可以使用 "/" 操作符进行遍历。

Path.name

   最终的路径组成部分。

Path.open(mode='r', *, pwd, **)

   在当前路径上发起调用 "ZipFile.open()"。 允许通过支持的模式打开用于
   读取或写入文本或二进制数据: 'r', 'w', 'rb', 'wb'。 当以文本模式打开
   时位置和关键字参数会被传给 "io.TextIOWrapper"，在其他情况下则会被忽
   略。 "pwd" 是要传给 "ZipFile.open()"  的 "pwd" 形参。

   3.9 版更變: 增加了对以文本和二进制模式打开的支持。 现在默认为文本模
   式。

Path.iterdir()

   枚举当前目录的子目录。

Path.is_dir()

   如果当前上下文引用了一个目录则返回 "True"。

Path.is_file()

   如果当前上下文引用了一个文件则返回 "True"。

Path.exists()

   如果当前上下文引用了 zip 文件内的一个文件或目录则返回 "True"。

Path.read_text(*, **)

   读取当前文件为 unicode 文本。 位置和关键字参数会被传递给
   "io.TextIOWrapper" ("buffer" 除外，它将由上下文确定)。

Path.read_bytes()

   读取当前文件为字节串。


PyZipFile 对象
==============

"PyZipFile" 构造器接受与 "ZipFile" 构造器相同的形参，以及一个额外的形
参 *optimize*。

class zipfile.PyZipFile(file, mode='r', compression=ZIP_STORED, allowZip64=True, optimize=-1)

   3.2 版新加入: *optimize* 形参。

   3.4 版更變: 默认启用 ZIP64 扩展。

   实例在 "ZipFile" 对象所具有的方法以外还附加了一个方法:

   writepy(pathname, basename='', filterfunc=None)

      查找 "*.py" 文件并将相应的文件添加到归档。

      如果 "PyZipFile" 的 *optimize* 形参未给定或为 "-1"，则相应的文件
      为 "*.pyc" 文件，并在必要时进行编译。

      如果 "PyZipFile" 的 *optimize* 形参为 "0", "1" 或 "2"，则限具有
      相应优化级别 (参见 "compile()") 的文件会被添加到归档，并在必要时
      进行编译。

      如果 *pathname* 是文件，则文件名必须以 ".py" 为后缀，并且只有 (
      相应的 "*.pyc") 文件会被添加到最高层级（不带路径信息）。 如果
      *pathname* 不是以 ".py" 为后缀的文件，则将引发 "RuntimeError"。
      如果它是目录，并且该目录不是一个包目录，则所有的 "*.pyc" 文件会
      被添加到最高层级。 如果目录是一个包目录，则所有的 "*.pyc" 会被添
      加到包名所表示的文件路径下，并且如果有任何子目录为包目录，则会以
      排好的顺序递归地添加这些目录。

      *basename* 仅限在内部使用。

      如果给定 *filterfunc*，则它必须是一个接受单个字符串参数的函数。
      在将其添加到归档之前它将被传入每个路径（包括每个单独的完整路径）
      。 如果 *filterfunc* 返回假值，则路径将不会被添加，而如果它是一
      个目录则其内容将被忽略。 例如，如果我们的测试文件全都位于 "test"
      目录或以字符串 "test_" 打头，则我们可以使用一个 *filterfunc* 来
      排除它们:

         >>> zf = PyZipFile('myprog.zip')
         >>> def notests(s):
         ...     fn = os.path.basename(s)
         ...     return (not (fn == 'test' or fn.startswith('test_')))
         >>> zf.writepy('myprog', filterfunc=notests)

      "writepy()" 方法会产生带有这样一些文件名的归档:

         string.pyc                   # Top level name
         test/__init__.pyc            # Package directory
         test/testall.pyc             # Module test.testall
         test/bogus/__init__.pyc      # Subpackage directory
         test/bogus/myfile.pyc        # Submodule test.bogus.myfile

      3.4 版新加入: *filterfunc* 形参。

      3.6.2 版更變: *pathname* 形参接受一个 *path-like object*。

      3.7 版更變: 递归排序目录条目。


ZipInfo 对象
============

"ZipInfo" 类的实例会通过 "getinfo()" 和 "ZipFile" 对象的 "infolist()"
方法返回。 每个对象将存储关于 ZIP 归档的一个成员的信息。

有一个类方法可以为文件系统文件创建 "ZipInfo" 实例:

classmethod ZipInfo.from_file(filename, arcname=None, *, strict_timestamps=True)

   为文件系统中的文件构造一个 "ZipInfo" 实例，并准备将其添加到一个 zip
   文件。

   *filename* 应为文件系统中某个文件或目录的路径。

   如果指定了 *arcname*，它会被用作归档中的名称。 如果未指定 *arcname*
   ，则所用名称与 *filename* 相同，但将去除任何驱动器盘符和打头的路径
   分隔符。

   *strict_timestamps* 参数在设为 "False" 时允许压缩早于 1980-01-01 的
   文件，代价时会将时间戳设为 1980-01-01。 类似的行为也会对晚于
   2107-12-31 的文件发生，时间戳也会被设为该上限值。

   3.6 版新加入.

   3.6.2 版更變: *filename* 形参接受一个 *path-like object*。

   3.8 版新加入: *strict_timestamps* 仅限关键字参数

实例具有下列方法和属性:

ZipInfo.is_dir()

   如果此归档成员是一个目录则返回 "True"。

   这会使用条目的名称：目录应当总是以 "/" 结尾。

   3.6 版新加入.

ZipInfo.filename

   归档中的文件名称。

ZipInfo.date_time

   上次修改存档成员的时间和日期。这是六个值的元组：

   +---------+----------------------------+
   | 索引    | 值                         |
   |=========|============================|
   | "0"     | Year (>= 1980)             |
   +---------+----------------------------+
   | "1"     | 月（1为基数）              |
   +---------+----------------------------+
   | "2"     | 月份中的日期（1为基数）    |
   +---------+----------------------------+
   | "3"     | 小时（0为基数）            |
   +---------+----------------------------+
   | "4"     | 分钟（0为基数）            |
   +---------+----------------------------+
   | "5"     | 秒（0为基数）              |
   +---------+----------------------------+

   備註:

     ZIP文件格式不支持1980年以前的时间戳。

ZipInfo.compress_type

   归档成员的压缩类型。

ZipInfo.comment

   "bytes" 对象形式的单个归档成员的注释。

ZipInfo.extra

   扩展字段数据。 PKZIP Application Note 包含一些保存于该 "bytes" 对象
   中的内部结构的注释。

ZipInfo.create_system

   创建 ZIP 归档所用的系统。

ZipInfo.create_version

   创建 ZIP 归档所用的 PKZIP 版本。

ZipInfo.extract_version

   需要用来提取归档的 PKZIP 版本。

ZipInfo.reserved

   必须为零。

ZipInfo.flag_bits

   ZIP 标志位。

ZipInfo.volume

   文件头的分卷号。

ZipInfo.internal_attr

   内部属性。

ZipInfo.external_attr

   外部文件属性。

ZipInfo.header_offset

   文件头的字节偏移量。

ZipInfo.CRC

   未压缩文件的 CRC-32。

ZipInfo.compress_size

   已压缩数据的大小。

ZipInfo.file_size

   未压缩文件的大小。


命令行界面
==========

"zipfile" 模块提供了简单的命令行接口用于与 ZIP 归档的交互。

如果你想要创建一个新的 ZIP 归档，请在 "-c" 选项后指定其名称然后列出应
当被包含的文件名:

   $ python -m zipfile -c monty.zip spam.txt eggs.txt

传入一个字典也是可接受的:

   $ python -m zipfile -c monty.zip life-of-brian_1979/

如果你想要将一个 ZIP 归档提取到指定的目录，请使用 "-e" 选项:

   $ python -m zipfile -e monty.zip target-dir/

要获取一个 ZIP 归档中的文件列表，请使用 "-l" 选项:

   $ python -m zipfile -l monty.zip


命令行选项
----------

-l <zipfile>
--list <zipfile>

   列出一个 zipfile 中的文件名。

-c <zipfile> <source1> ... <sourceN>
--create <zipfile> <source1> ... <sourceN>

   基于源文件创建 zipfile。

-e <zipfile> <output_dir>
--extract <zipfile> <output_dir>

   将 zipfile 提取到目标目录中。

-t <zipfile>
--test <zipfile>

   检测 zipfile 是否有效。


解压缩的障碍
============

zipfile 模块的提取操作可能会由于下面列出的障碍而失败。


由于文件本身
------------

解压缩可能由于不正确的密码 / CRC 校验和 / ZIP 格式或不受支持的压缩 /
解密方法而失败。


文件系统限制
------------

超出特定文件系统上的限制可能会导致解压缩失败。 例如目录条目所允许的字
符、文件名的长度、路径名的长度、单个文件的大小以及文件的数量等等。


资源限制
--------

缺乏内存或磁盘空间将会导致解压缩失败。 例如，作用于 zipfile 库的解压缩
炸弹 (即 ZIP bomb) 就可能造成磁盘空间耗尽。


中断
----

在解压缩期间中断执行，例如按下 ctrl-C 或杀死解压缩进程可能会导致归档文
件的解压缩不完整。


提取的默认行为
--------------

不了解提取的默认行为可能导致不符合期望的解压缩结果。 例如，当提取相同
归档两次时，它会不经询问地覆盖文件。
