> 文章列表 > 解压你的压缩:Python ZipFile 实战指南(一)ZipFile 类和它的参数们

解压你的压缩:Python ZipFile 实战指南(一)ZipFile 类和它的参数们

解压你的压缩:Python ZipFile 实战指南(一)ZipFile 类和它的参数们

文章目录

  • 参考
  • 描述
  • 铺垫
      • Zip 文件
      • ZipFile 模块
      • Zip 文件格式规范
      • PKWARE
  • ZipFile
      • file
          • file 参数为字符串类型的文件路径
          • file 参数为一个文件对象
      • mode
      • compression
      • allowZip64
          • 中央结构目录
          • Zip64
          • zipfile.LargeZipFile
      • compresslevel
      • strict_timestamps

参考

项目 描述
维基百科 ZIP 格式
Python 官方文档 zipfile - 使用ZIP存档
搜索引擎 GoogleBing
Zip 文件格式规范 APPNOTE.TXT

描述

项目 描述
Python 3.10.6
操作系统 Windows 10 专业版(x86-64)

铺垫

Zip 文件

ZIP 文件格式是一种数据压缩和文档储存的文件格式,原名 Deflate,发明者为菲尔·卡茨(Phil Katz),他于1989年1月公布了该格式的资料。ZIP通常使用后缀名 .zip,它的 MIME 格式为 application/zip。目前,ZIP格式属于几种主流的压缩格式之一,其竞争者包括RAR格式以及开放源码的 7z 格式。从性能上比较,RAR 及 7z 格式较 ZIP 格式压缩率较高,而7-Zip由于提供了免费的压缩工具而逐渐在更多的领域得到应用。Microsoft从Windows ME操作系统开始内置对zip格式的支持,即使用户的电脑上没有安装解压缩软件,也能打开和制作zip格式的压缩文件,OS X和流行的Linux操作系统也对zip格式提供了类似的支持。因此如果在网络上传播和分发文件,zi p格式往往是最常用的选择。

ZipFile 模块

zipfile 模块是 Python 标准库 中用于处理 Zip 文件的模块。它提供了一系列的函数和类,可以方便地进行 Zip 文件的创建、读取和解压缩操作。

Zip 文件格式规范

APPNOTE.TXT 是一个关于 Zip 文件格式的官方规范文档,被广泛引用和使用。文档提供了详细的技术细节和规范,包括文件格式结构、文件存储方式、压缩算法、加密方式、注释信息、时间戳等等。
该文档由 PKWARE 公司发布,该公司也是 Zip 格式的发明者和开发者。由于 Zip 文件格式的普及,该规范文档被广泛引用,同时也影响了其他一些压缩文件格式的设计。因此,对于使用 Zip 文件的人来说,了解该规范文档对于正确地操作 Zip 文件是非常重要的。

PKWARE

PKWARE 是一家总部位于美国威斯康星州密尔沃基的软件公司,专门从事数据压缩和数据保护技术。该公司是数据压缩标准 ZIP 格式的创始人之一,还创建了许多其他压缩和加密技术,包括 PKZIP、SecureZIP、Smartcrypt 和 PKWARE Data Security 等产品。PKWARE 的产品被广泛用于数据压缩和加密、数据备份和恢复、数据存储和传输等地方。

ZipFile

ZipFile 类是 zipfile 模块中最重要的类之一,它提供了一系列的方法,用于创建、读取和解压缩 Zip 文件。

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

file

ZipFile 类的 file 参数用于指定 Zip 文件的名称或路径。该参数的值可以是一个字符串类型的文件路径,也可以是一个文件对象。

file 参数为字符串类型的文件路径

举个栗子

from zipfile import ZipFile# 指定需要被压缩的文件
FILEPATH = r'C:\\Users\\RedHeart\\PycharmProjects\\pythonProject\\月亮与六便士.txt'
# 指定被创建的 Zip 文件所处的路径
ZIPPATH = r'C:\\Users\\RedHeart\\PycharmProjects\\pythonProject\\月亮与六便士.zip'# 以覆盖模式(若 ZIP 文件尚不存在,则创建它,若
# Zip 文件已经存在,则覆盖它)打开 ZIP 文件
fz = ZipFile(ZIPPATH, mode='w')# 将目标文件写入 Zip 压缩文件中
# write() 的第一个参数用于指定需要写入 Zip 压缩文件中
# 的文件所处的路径,第二个参数用于指定该文件在 Zip 压缩
# 文件中所处的路径。
fz.write(FILEPATH, arcname='月亮与六便士.txt')# 输出 Zip 压缩文件中的文件列表
fz.printdir()# 关闭 Zip 文件
fz.close()

执行效果

File Name                                             Modified             Size
月亮与六便士.txt                                     2023-04-22 16:01:22       315564
file 参数为一个文件对象

ZipFile 与上下文管理器

ZipFile 对象实现了上下文管理器接口,因此可以使用 with 语句来打开和关闭 ZIP 文件。使用上下文管理器可以确保在离开 with 代码块时,文件被自动关闭,避免了因为代码异常而导致文件句柄没有正确释放的问题。

举个栗子

from zipfile import ZipFileFILEPATH = r'C:\\Users\\RedHeart\\PycharmProjects\\pythonProject\\月亮与六便士.txt'
ZIPPATH = r'C:\\Users\\RedHeart\\PycharmProjects\\pythonProject\\月亮与六便士.zip'# 以二进制可读写模式打开 ZIP 文件,
# 若该文件不存在则创建它;若该文件存在,
# 则覆盖它。
with open(ZIPPATH, 'wb+') as fo:with ZipFile(fo, 'w') as fz:fz.write(FILEPATH, arcname='月亮与六便士')fz.printdir()

执行效果

File Name                                             Modified             Size
月亮与六便士                                         2023-04-22 16:01:22       315564

注:

若使用文件对象作为 ZipFile()file 参数的值,那么你需要保证该文件对象是以二进制模式的方式进行打开的。否则在使用 write() 等方法对 Zip 文件对象进行操作时可能将引发错误。对此,请参考如下示例:

from zipfile import ZipFileFILEPATH = r'C:\\Users\\RedHeart\\PycharmProjects\\pythonProject\\月亮与六便士.txt'
ZIPPATH = r'C:\\Users\\RedHeart\\PycharmProjects\\pythonProject\\月亮与六便士.zip'# 使用文本模式下的可读写模式打开 Zip 文件
with open(ZIPPATH, 'w+') as fo:with ZipFile(fo, 'w') as fz:fz.write(FILEPATH, arcname='月亮与六便士')fz.printdir()

输出错误信息

TypeError: write() argument must be str, not bytes

mode

ZipFile 类的 mode 参数用于指定 Zip 文件的打开或创建模式,该参数的值可以是 r、w、x 或 a。

  1. r
    mode 参数的 默认值r,表示以只读方式打开 zip 文件。如果文件不存在,则会引发异常 FileNotFoundError

  2. w
    以覆盖方式打开 Zip 文件。若目标 Zip 文件已经存在,则该文件将被覆盖。若目标文件尚不存在,则创建它。

  3. x
    以排它方式进行 Zip 文件的创建。若文件已经存在,则会引发 FileExistsError 异常。

  4. a
    以追加方式打开 Zip 文件。若文件已经存在,则在该文件的末尾进行文件的写入。若目标文件尚不存在,则创建它。

只读模式与读或写的操作

上述模式中,仅当将 Zip 文件的模式指定为 r 时,你才不具有对 Zip 文件进行写的权力。在另外三种模式下,你均可以对 Zip 文件进行读或写的操作。

compression

ZipFile 类的 compression 参数用于指定压缩文件时使用的压缩算法,它可以被设置为以下四个值之一:ZIP_STOREDZIP_DEFLATEDZIP_BZIP2ZIP_LZMA

项目 描述
ZIP_STORED 该值为 copression 参数的 默认值。不进行任何压缩,直接存储原始数据,通常使用该压缩算法对文件进行归档(将多个文件归并为一个文件,便于文件的存储与转移)。
ZIP_DEFLATED 指定使用 Deflate 压缩算法,该算法是 ZIP 文件中最常用的压缩算法之一。Deflate 算法能够提供比较高的压缩率和较快的压缩和解压速度,适用于大多数压缩场景。
ZIP_BZIP2 指定使用 Bzip2 压缩算法。与 Deflate 算法相比,Bzip2算法可以获得更高的压缩率,但压缩和解压速度较慢,适用于需要获得更高压缩率的场景。
ZIP_LZMA 指定使用 LZMA 压缩算法。LZMA 算法可以提供比 Bzip2 更高的压缩率,但压缩和解压速度更慢,并且需要更多的内存。因此,ZIP_LZMA 适用于需要获得极高压缩率并且可以承受较慢的压缩和解压速度的场景。

allowZip64

ZipFile 类的 compression 参数用于指定 Zip 文件在必要情况下是否可以使用 Zip64 格式来支持超过 4GB 的文件。

中央结构目录

中央结构目录

中央目录结构是 ZIP 文件格式的一部分,它存储了 ZIP 文件中包含的所有文件和目录的元数据信息,如文件名、文件属性、文件的压缩前和压缩后的大小等。

Zip 内存储的文件的位置和大小

中央目录结构还需要记录 ZIP 文件内存储的文件的位置和大小,这是因为 ZIP 文件是一种归档文件格式,其中的文件通常都经过了压缩处理,不像普通的文件系统一样,可以直接访问。

因此,当需要解压缩 ZIP 文件中的某个文件时,需要知道该文件的存储位置和大小,以便可以正确地读取和还原该文件。中央目录结构中存储的位置和大小信息可以帮助 ZIP 工具在解压缩和操作 ZIP 文件时快速地定位和处理文件,确保 ZIP 文件的正确性和完整性。

完整性

此外,中央目录结构还可以用于查看 ZIP 文件的内容列表,以及检查 ZIP 文件的完整性和有效性,因为 中央目录结构记录了文件的元数据信息,可以用于验证 ZIP 文件中是否存在任何损坏或缺失的文件

Zip64

在传统的 Zip 文件格式中,每个 Zip 文件内的所有文件和目录都由一个中央目录结构引用,而该结构中存储文件大小和位置的字段只有 4 个字节,使用 2^32-1 个二进制位来记录信息,所能表示的最大容量位 4GB。因此,传统的 Zip 文件格式的限制是单个文件不能超过 4GB。如果需要支持超过 4GB 的文件,则需要使用 Zip64 格式。Zip64 格式使用 8 字节的字段来存储文件大小和位置,可以处理更大的文件和归档文件。

zipfile.LargeZipFile

倘若你尝试在没有使用 Zip64 扩展格式时压缩占用空间超过 4GB 的文件,Python 将抛出如下异常信息并停止压缩文件。

zipfile.LargeZipFile: Filesize would require ZIP64 extensions

compresslevel

compresslevel 形参控制在将文件进行压缩时将使用的压缩等级,压缩等级越高,压缩后文件的体积越小,但压缩和解压缩过程会相应的增加。

注:

  1. 当压缩算法使用的是 ZIP_STOREDZIP_LZMA 时指定压缩等级将不会产生任何变化。

  2. 当使用 ZIP_DEFLATED 作为压缩算法时,压缩等级可在 -1 ~ 9 范围内;当使用 ZIP_BZIP2 作为压缩算法时,压缩等级可在 1 ~ 9 范围内。

  3. 当使用 ZIP_DEFLATED 作为压缩算法时,其默认的压缩等级为 -1,该压缩等级是速度和压缩率之间的平衡 (一般相当于设压缩等级为 6)。

  4. 当使用 ZIP_DEFLATED 作为压缩算法时,若将压缩等级设定为 0,则其产生的效果与 ZIP_STORED 无异。

  5. 当使用 ZIP_BZIP2 作为压缩算法时,其默认的压缩等级为 9

strict_timestamps

strict_timestamps 参数是用于控制是否允许压缩早于 1980 年或晚于 2107 年的文件,并且在压缩这些文件时是否将时间戳设置为最小或最大允许值。
当 strict_timestamps 参数为 False 时,zipfile.ZipFile 类会允许压缩早于 1980 年或晚于 2107 年的文件,并将这些文件的时间戳设为 1980 年 1 月 1 日2107 年 12 月 31 日。对此,请参考如下示例:

import os
from zipfile import ZipFile# 获取目标文件的访问时间戳
atime = os.path.getatime('月亮与六便士.txt')
# 将目标文件的修改时间戳设置为 1970 年 1 月 1 日 8:00:00
os.utime('月亮与六便士.txt', (atime, 0))FILEPATH = r'C:\\Users\\RedHeart\\PycharmProjects\\pythonProject\\月亮与六便士.txt'
ZIPPATH = r'C:\\Users\\RedHeart\\PycharmProjects\\pythonProject\\月亮与六便士.zip'# 尝试将早于 1980 年的文件写入 Zip 文件中
with open(ZIPPATH, 'wb+') as fo:with ZipFile(ZIPPATH, 'w', strict_timestamps=False) as fz:fz.write(FILEPATH, arcname='月亮与六便士.txt')fz.printdir()

执行效果

File Name                                             Modified             Size
月亮与六便士.txt                                     1980-01-01 00:00:00       315564

如果您需要在压缩文件时保留原始时间戳,则可以将 strict_timestamps 参数设置为 True(默认值),但这可能会导致无法压缩某些文件。对此,请参考如下示例:

import os
from zipfile import ZipFile# 获取目标文件的访问时间戳
atime = os.path.getatime('月亮与六便士.txt')
# 将目标文件的修改时间戳设置为 1970 年 1 月 1 日 8:00:00
os.utime('月亮与六便士.txt', (atime, 0))FILEPATH = r'C:\\Users\\RedHeart\\PycharmProjects\\pythonProject\\月亮与六便士.txt'
ZIPPATH = r'C:\\Users\\RedHeart\\PycharmProjects\\pythonProject\\月亮与六便士.zip'# 尝试将早于 1980 年的文件写入 Zip 文件中
with open(ZIPPATH, 'wb+') as fo:with ZipFile(ZIPPATH, 'w') as fz:fz.write(FILEPATH, arcname='月亮与六便士.txt')

执行效果

由于在 strict_timestamps=True 时尝试将修改时间早于 1980 年 1 月 1 日 的文件写入 Zip 文件中,Python 抛出了 ValueError 异常错误。

ValueError: ZIP does not support timestamps before 1980

注:

strict_timestamps 针对的时间戳为文件的修改时间戳(文件最后一次修改的时间所对应的时间戳信息),在将文件输入到压缩包中时,写入的也仅仅为文件的修改时间戳(文件的创建时间戳、元数据更改时间戳,访问时间戳等时间戳信息并不会写入 Zip 文件中)。