zipfile — 使用 ZIP 档案 — Python 文档

来自菜鸟教程
Python/docs/3.8/library/zipfile
跳转至:导航、​搜索

zipfile — 使用 ZIP 档案

源代码: :source:`Lib/zipfile.py`



ZIP 文件格式是一种常见的存档和压缩标准。 此模块提供用于创建、读取、写入、附加和列出 ZIP 文件的工具。 该模块的任何高级使用都需要了解 PKZIP 应用说明 中定义的格式。

此模块当前不处理多磁盘 ZIP 文件。 它可以处理使用 ZIP64 扩展名的 ZIP 文件(即大小超过 4 GiB 的 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 兼容包装器。 有关详细信息,请参阅 路径对象 部分。

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 Objects 部分中进行了描述。
zipfile.is_zipfile(filename)

如果 filename 是基于幻数的有效 ZIP 文件,则返回 True,否则返回 Falsefilename 也可以是文件或类文件对象。

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 可以是文件路径(字符串)、类文件对象或 类路径对象

mode 参数应该是 'r' 读取现有文件,'w' 截断和写入新文件,'a' 附加到现有文件,或 'x' 专门创建和写入新文件。 如果 mode'x' 并且 file 引用现有文件,则会引发 FileExistsError。 如果 mode'a' 并且 file 是指现有的 ZIP 文件,则会向其中添加其他文件。 如果 file 不是 ZIP 文件,则会将新的 ZIP 存档附加到该文件。 这意味着将 ZIP 存档添加到另一个文件(例如 python.exe)。 如果 mode'a' 并且文件根本不存在,则创建它。 如果 mode'r''a',文件应该是可查找的。

compression 是写入存档时使用的 ZIP 压缩方法,应该是 ZIP_STOREDZIP_DEFLATEDZIP_BZIP2 或 [XIP_LZ] ; 无法识别的值将导致 NotImplementedError 被引发。 如果指定了 ZIP_DEFLATEDZIP_BZIP2ZIP_LZMA 但相应的模块 (zlib、bz2] 或 [X114X] lzma) 不可用,引发 RuntimeError。 默认值为 ZIP_STORED

如果 allowZip64True(默认值),当 zipfile 大于 4 GiB 时,zipfile 将创建使用 ZIP64 扩展名的 ZIP 文件。 如果是 false zipfile 将在 ZIP 文件需要 ZIP64 扩展名时引发异常。

compresslevel 参数控制将文件写入存档时使用的压缩级别。 当使用 ZIP_STOREDZIP_LZMA 时,它不起作用。 使用 ZIP_DEFLATED 时,接受整数 09(有关更多信息,请参阅 zlib)。 使用 ZIP_BZIP2 时,接受整数 19(有关详细信息,请参阅 bz2)。

strict_timestamps 参数设置为 False 时,允许压缩早于 1980-01-01 的文件,但代价是将时间戳设置为 1980-01-01。 比 2107-12-31 更新的文件也会出现类似行为,时间戳也设置为限制。

如果文件是用 'w''x''a' 模式创建的,然后 关闭 没有向存档添加任何文件,则适当的 ZIP 结构用于空存档将写入文件。

ZipFile 也是一个上下文管理器,因此支持 with 语句。 在示例中, myzipwith 语句的套件完成后关闭 - 即使发生异常:

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

3.2 版新功能: 添加了使用 ZipFile 作为上下文管理器的功能。

3.3 版更改: 添加了对 bzip2lzma 压缩的支持。

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

在 3.5 版更改: 添加了对写入不可搜索流的支持。 添加了对 'x' 模式的支持。

在 3.6 版中更改: 以前,对于无法识别的压缩值,会引发一个普通的 RuntimeError

在 3.6.2 版更改: file 参数接受 类路径对象

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

写入文件时,如果文件大小不知道但可能超过2GiB,则通过force_zip64=True确保头格式能够支持大文件。 如果预先知道文件大小,则构造一个 ZipInfo 对象并设置 file_size,并将其用作 name 参数。

笔记

open()read()extract() 方法可以采用文件名或 ZipInfo 对象。 当您尝试读取包含重名成员的 ZIP 文件时,您会很感激这一点。

3.6 版更改: 移除了对 mode='U' 的支持。 使用 io.TextIOWrapper通用换行符 模式下读取压缩文本文件。

在 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 变为foo\bar 在 Windows 上。 并且成员文件名中的所有 ".." 组件将被删除,例如:../../foo../../ba..r 变为 foo../ba..r。 在 Windows 上非法字符(:<>|"?*) 替换为下划线 (_)。

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() 设置的默认密码。 在使用除 ZIP_STOREDZIP_DEFLATEDZIP_BZIP2 或 [X145LX] 以外的压缩方法的 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,可以是strbytes实例; 如果是 str,则首先将其编码为 UTF-8。 zinfo_or_arcname 要么是它在存档中给出的文件名,要么是一个 ZipInfo 实例。 如果是实例,则至少必须给出文件名、日期和时间。 如果是名称,则日期和时间设置为当前日期和时间。 存档必须以 'w''x''a' 模式打开。

如果给定,compress_type 会覆盖为新条目的构造函数或 zinfo_or_arcname(如果是 ZipInfo 实例)。 类似地, compresslevel 将覆盖构造函数(如果给定)。

笔记

当将 ZipInfo 实例作为 zinfo_or_arcname 参数传递时,使用的压缩方法将是给定 ZipInfocompress_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 个字节。 超过此长度的评论将被截断。


路径对象

class zipfile.Path(root, at=)

root zipfile(可能是 ZipFile 实例或 file 适合传递给 ZipFile 构造函数)构造一个 Path 对象。

at 指定这个 Path 在 zipfile 中的位置,例如 'dir/file.txt'、'dir/' 或 。 默认为空字符串,表示根。

路径对象公开了 pathlib.Path 对象的以下特性:

路径对象可以使用 / 操作符遍历。

Path.name
最后的路径组件。
Path.open(*, **)

在当前路径上调用 ZipFile.open()。 接受与 ZipFile.open() 相同的参数。

警告

此函数的签名在 Python 3.9 中以不兼容的方式更改。 对于未来兼容的版本,请考虑使用第三方 zpp.Path 包(3.0 或更高版本)。

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 新功能:优化参数。

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

除了 ZipFile 对象的方法之外,实例还有一种方法:

writepy(pathname, basename=, filterfunc=None)

搜索文件 *.py 并将相应文件添加到存档中。

如果没有给 PyZipFileoptimize 参数或 -1,则对应的文件是 *.pyc 文件,必要时编译。

如果 PyZipFileoptimize 参数是 012,则只有具有该优化级别的文件(请参阅 ]compile()) 被添加到档案中,必要时进行编译。

如果pathname为文件,则文件名必须以.py结尾,并且只在顶层添加(对应*.pyc)文件(无路径信息)。 如果 pathname 是不以 .py 结尾的文件,则会引发 RuntimeError。 如果是目录,而该目录又不是包目录,则将所有文件*.pyc加在最上层。 如果目录是包目录,则将所有的*.pyc作为文件路径添加到包名下,如果有子目录是包目录,则按照排序顺序递归添加。

basename 仅供内部使用。

filterfunc,如果给定,必须是一个接受单个字符串参数的函数。 在将其添加到存档之前,它将传递每个路径(包括每个单独的完整文件路径)。 如果 filterfunc 返回 false 值,则不会添加路径,如果是目录,则其内容将被忽略。 例如,如果我们的测试文件都在 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 版更改: 路径名 参数接受 类路径对象

3.7 版更改: 递归对目录条目进行排序。


ZipInfo 对象

ZipInfo 类的实例由 ZipFile 对象的 getinfo()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 版更改: 文件名 参数接受 类路径对象

3.8 版新功能:strict_timestamps 仅关键字参数

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

ZipInfo.is_dir()

如果此存档成员是目录,则返回 True

这使用条目的名称:目录应始终以 / 结尾。

3.6 版中的新功能。

ZipInfo.filename
存档中文件的名称。
ZipInfo.date_time

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

指数

价值

0

年份 (>= 1980)

1

月(以一位为单位)

2

一个月中的第几天(以一个为单位)

3

小时(从零开始)

4

分钟(从零开始)

5

秒(从零开始)

笔记

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

ZipInfo.compress_type
归档成员的压缩类型。
ZipInfo.comment
作为 bytes 对象的单个存档成员的注释。
ZipInfo.extra
扩展字段数据。 PKZIP 应用笔记 包含一些关于包含在这个 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格式不正确或不支持的压缩方法/解密,解压可能会失败。


文件系统限制

超过对不同文件系统的限制会导致解压失败。 如目录项中允许的字符、文件名的长度、路径名的长度、单个文件的大小、文件数等。


资源限制

内存或磁盘容量不足会导致解压失败。 例如,解压炸弹(又名 ZIP 炸弹)适用于 zipfile 库,会导致磁盘容量耗尽。


中断

解压过程中的中断,如按control-C或杀死解压过程可能会导致档案解压不完全。


提取的默认行为

不知道默认的提取行为可能会导致意外的解压结果。 例如,当两次提取同一个存档时,它会在不询问的情况下覆盖文件。