一、引言
分享知识+推广我的Python书。
本次分享的是用Python把zip格式的压缩文件解压缩的几种方法。本文将介绍三种解压缩zip文件的方法:
使用shutil 标准库的unpack_archive对象解压缩
使用unzip.exe以命令行方式解压缩
使用zipfile标准库解压缩




unpack_archive 的使用格式如下:
unpack_archive(filename, extract_dir=None, format=None)
第一个参数是被解压缩的文件名。
第二个参数是解压之后放到什么目录,这个参数可以没有,如果没有,则解压到当前目录下。
第三个参数是压缩文件的格式,如果不提供,将检查压缩文件格式是否"zip", "tar", "gztar", "bztar", "xztar" 或其它可以识别的格式,如果不能识别是什么格式,则抛出异常。

这段是基本的解压缩代码,功能是把当前目录下的 1.zip 解压到当前目录下。这里的变量 zipfn 表示被解压缩的文件名,我们为它赋值时,可以只有文件名,也可以带相对路径,也可以带绝对路径。
还有一种指定解压缩路径的用法:

上述代码运行后,会把压缩文件解压到指定的目录下,解压缩之后,会保留压缩包内的文件和目录结构不变。指定的解压缩目录可以不存在,解压缩的时候会自动创建这个目录。
用 unpack_archive 来解压缩,用法简单,但有两个缺点:
第一、不能解压缩带密码的zip压缩文件;
第二、对于某些文件名是中文的zip压缩文件,解压出来之后文件名是乱码。 make_archive创建的压缩文件不存在这种现象,winrar压缩出来的zip文件存在这种现象。

http://gnuwin32.sourceforge.net/downlinks/unzip-bin-zip.php
(1)无密码解压缩,解压到当前目录
unzip ab.zip
(2)无密码解压缩,解压到指定目录
unzip ab.zip -d tmp
(3)有密码解压缩,解压到当前目录
unzip -P 123456 ab.zip
(4)有密码解压缩,解压到指定目录
unzip -P 123456 ab.zip -d tmp

用zipfile解压缩zip文件,我们需要导入两个对象:
from zipfile import ZipFile, is_zipfile
其中,is_zipfile可以判断一个文件是否压缩文件,ZipFile可以打开一个zip压缩文件,打开之后后续再进一步操作。
1、判断是否zip文件
使用 is_zipfile 不需要打开 zip 文件,直接用文件名去判断就行了。不过,也有误判的时候,因为Word文件也会被判定为zip文件。

用zipfile标准库去解压缩Word文件,也能解出一堆文件来,但这不是我们所关心的,我们关心的是解压缩真正的zip文件。
为了判断真正的zip压缩文件,我们可以先检查扩展名是否 .zip ,再用 is_zipfile 判断一下,这样误判的概率就很小了。
2、解压缩无密码的zip压缩文件
对于真正的zip文件,最简单的解压缩操作是解压全部内容,程序代码写起来比较简单,如下所示。

这段代码是把当前目录下的zip文件 1.zip 中的全部内容解压到当前目录。如果是解压到指定目录,我们可以用如下代码:


上面的代码是用 zpf 对象的 extract 方法,把压缩包内的文件列表中的文件一个个释放到指定的目录。
有的时候我们需要提取压缩文件内的个别文件,就可以在上面代码的基础上加一个选择语句判断一下是否需要的文件,代码示例如下。

3、解压缩有密码的zip压缩文件


注意 pwd 参数的值需要转换成 UTF-8 编码的字节串。
也有一些程序不是怎么处理密码的,它们不是为 zp 对象的 extractall 方法和 extract 方法增加一个 pwd 参数,而是在打开 zip 文件之后先用 zp 对象的 setpassword 方法预填充一下密码,后面解压缩的时候就无需带 pwd 参数了。

不少人以为 zp 对象的 setpassword 方法是用来在压缩时创建密码的,其实这种观点是不对的,它的真正作用是在解压缩时用来预填充密码。
不过,这个 setpassword 方法如果预填充的密码不正确,它不会给出任何提示,到解压缩的环节还是会报错。
如果想在预填充密码的环节就知道密码对不对,我们可以用下面的方法。

4、关于解压缩乱码的问题
有些zip压缩文件内包含中文文件名,解压缩之后是乱码。看下面的例子。
有一个文件名叫“示例.txt”,用 WinRAR 压缩成 “示例.zip”,再用下面的代码解压缩就会得到一个乱码文件,文件名变成了“╩╛└²”。

造成乱码的原因是 zipfile 标准库只认 utf-8 编码 和 cp437 编码,只要不确定是 utf-8 编码,它就一律认为是 cp437编码,相当一部分包含汉子的文件名在加压缩时被认成了 cp437 编码,所以发生了乱码现象。解决办法是逐个获取zip压缩文件的文件名,然后根据一些信息在确定该文件的编码不是 utf-8 之后直接用指定编码来解压缩该文件即可。在咱们中文Windows操作系统中,我们指定用 gb18030 编码就行。
具体操作思路请看下面的例子。





