用 Python 压缩文件方法汇总
2021-09-15
对于流行的文件压缩格式,如 tar 、zip 、gzip 、bz2 等,乃至于更奇特的 lzma 等格式,Python 都能轻易实现。本文将对有关压缩文件的问题给予阐述。
压缩格式以及相关模块
Python 提供了几乎为所有现有压缩文件的工具,下面逐一领略。
zlib是一个 Python 库,能够实现zip、gzip格式文件的压缩和解压缩。bz2模块提供了对bzip2格式的压缩支持。它也只对单个文件起作用,因此不能归档。lzma既是算法的名称,也是 Python 模块。它可以产生比一些旧方法更高的压缩比,并且是xz(更具体地说是 LZMA2 )背后的算法。gzip是大多数人都熟悉的应用,此外它也是一个 Python 模块的名称。此模块使用前面提到的zlib压缩算法,并充当类似于实用程序gzip和gunzip的接口。shutils是一个模块,我们通常不把该模块与压缩和解压缩联系在一起。但它提供了处理归档文件的实用方法,便于生成tar、gztar、zip、bztar或者xztar这些类型的归档文件。顾名思义,
zipfile允许我们用 Python 中实现 zip 归档,提供了创建、读取、写入或追加zip文件所需的所有方法,还提供了便于操作这些文件的类和对象。和上面的
zipfile类似,tarfile这个模块用于实现tar归档,可以读取和写入gzip、bz2和lzma文件或归档文件。 也支持与常规的tar压缩软件能实现的其他功能。
压缩与解压缩
上面列出了很多选择,它们中有一些比较基本,有一些具有许多其他功能,但共同点显然是包含压缩功能。下面就来看看有关基本操作。
先看 zlib ,这是一个相当低级的库,因此可能不太常用,让我们来看看针对整个文件的压缩或解压缩方法。
1 | import zlib, sys |
上面的代码中所需要的输入文件,可以用 head -c 1MB </dev/zero > data 指令生成,此文件由零组成且大小为 1MB 。将文件读入内存滞后,用 zlib 中的 compress 方法创建压缩数据。然后将该数据写入输出文件。
为了证明能够恢复数据——解压缩,再次打开上述生成的压缩文件并对其通过 zlibb 的 decompress 方法。通过 print ,可以看到压缩和解压缩数据的大小都是匹配的。
下一个是 bz2 ,它的使用方式与上面的 zlib 非常相似:
1 | import bz2, os, sys |
不出所料,使用方法大同小异。为了显示一些不同之处,在上面的示例中,我们简化了压缩步骤,将其减少到1行,并使用 os.stat来检查文件的大小。
这些低级模块中的最后一个是 lzma ,为了避免反复显示相同的代码,这次执行增量压缩:
1 | import lzma, os |
首先创建一个输入文件,文件中包含从字典中提取的一组单词,该字典在 /usr/share/dict/words 中,这样可以确认解压后的数据与原始数据相同。
然后,我们像前面的示例一样打开输入和输出文件。然而,这一次在 1024 位块中迭代随机数据,并使用 LZMACompressor.compress 方法压缩它们。然后将这些块写入输出文件。在读取和压缩整个文件之后,我们需要调用 flush ,以完成压缩过程、并从压缩器中清除任何剩余数据。
为了证实上述操作的有效性,我们以通常的方式打开并解压缩文件,并从文件中打印出几个单词。
下面要研究高级别的模块。现在使用 gzip 执行相同的任务:
1 | import os, sys, shutil, gzip |
在这个例子中,结合了 gzip 和 shutils 。看起来我们所做的批量压缩与之前使用 zlib 或 bz2 的效果相同,但由于 shutil.copyfileobj 方法,我们实现了分块增量压缩,而不必像使用lzma那样循环数据。
gzip 模块的一个优点是:它还提供了命令行接口,我说的不是 Linux gzip 和 gunzip ,而是 Python 中所集成的:
1 | python3 -m gzip -h |
更高效的工具
如果你熟悉 zip 或 tar ,或者必须用其中的一种格式存档,就应该认真阅读下面的内容。除了基本的压缩或解压缩操作外,这两个模块还包括其他的一些实用方法,例如校验、使用密码、在归档文件中列出文件等。所以,很有必要深入研究一番,确保掌握这些技能。
1 | import zipfile |
上述代码有点长,它涵盖了 zipfile 模块的所有重要功能。在这段代码中,首先在 with 上下文管理中,以 w 模式使用 ZipFile创建 ZIP 归档文件,然后将文件添加到归档文件中。你会注意到,实际上不需要打开要添加的文件 —— 我们所需要做的就是调用 write 方法,并传入文件名为参数。添加所有文件后,我们还使用 setpassword 方法设置存档密码。
接下来,为了证明这种操作方法的有效性,打开归档文件。在读取任何文件之前,检查CRC和文件头,然后检索存档中所有文件的信息。在本例中,我们只打印 ZipInfo 对象的列表,但你也可以检查其属性,以获得CRC、大小、压缩类型等。
检查完所有文件后,打开并读取其中一个文件。我们看到它具有预期的内容,所以可以继续并将其解压缩都指定路径(/tmp/ )。
除了创建和读取归档文件或普通文件外,ZIP 还允许我们将文件追加到现有的存档中。为此,只需将访问模式更改为 a (追加模式):
1 | with zipfile.ZipFile(archive, "a") as zf: |
与 gzip 模块相同,Python的 zipfile 和 tarfile 也提供 CLI 。要执行基本存档和提取,请使用以下命令:
1 | python3 -m zipfile -c arch.zip words1.txt words2.txt # Create |
最后但并非最不重要的是 tarfile 模块。此模块类似于 zipfile ,但也实现了一些额外的功能:
1 | import tarfile |
我们从归档文件的基本创建开始,这里使用的打开模式 "w:gz" ,指定要使用 GZ 压缩。然后将所有的文件添加到存档中。使用 tarfile 模块,还可以传入符号链接(软连接)、或传入可以递归添加的整个目录。
接下来,为了确认所有文件都确实存在,我们使用 getmembers 方法。为了深入了解各个文件,可以使用 gettarinfo 方法,它提供了所有 Linux 文件属性。
tarfile 提供了一个我们在其他模块中没有看到的很酷的特性,那就是在将文件添加到归档文件时能够修改文件的属性。在上面的代码片段中,通过提供 filter 参数来更改文件的权限,该参数修改了 TarInfo.mode。此值必须作为八进制数提供,此处的 0o100600 将权限设置为 0600 或 -rw-------.。
为了在进行此更改后获得文件的完整概览,我们可以运行 list 方法,它提供类似于 ls -l的输出。
使用tar 存档的最后一件事是打开它并将其解压缩。为此,我们使用 "r:gz" 模式打开它,以文件名作为 getmember 方法的参数,返回文件对象,并将其解压缩到指定路径中。
1 | with tarfile.open(archive, "r:gz") as tar: |
结论
如你所见,Python 的提供了包括低级和高级、特定和通用、简单和复杂的各类模块或库。可以根据实际需要进行选择,通常建议使用通用模块,如 zipfile 或 tarfile ,只有在必要时才使用 lzma 之类的模块。
当然,要想熟练使用以上各个模块的各种方法,还是要阅读官方文档。
参考文献
https://towardsdatascience.com/all-the-ways-to-compress-and-archive-files-in-python-e8076ccedb4b
若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏
关注微信公众号,读文章、听课程,提升技能