(译)Python zipfile模块介绍

(译)Python zipfile模块介绍

Jan 20, 2014
Coding
Python

本文内容适用于 python 2.x 版本

原文链接:zipfile — Work with ZIP archives。翻译过程中结合了自己的理解,并给出了一些示例代码。

zip是一种常见的压缩格式,Python中提供了zipfile模块来支持zip格式压缩文件的操作,包括文件压缩、解压缩、查看压缩文件信息等,还支持加密文件的解密(不过解密速度慢,因为是使用Python完成,而非C语言),zipfile目前不支持文件的加密。通过设置zipfile.ZipFile()函数的allowZip64参数为True,可以支持大小超过4G的zip文件的操作。

zipfile模块包含的内容主要如下:

  • exception zipfile.BadZipfile:当zip文件破损时抛出的异常
  • exception zipfile.LargeZipfile:当文件过大,而且allowZip64也没有设置为True时,抛出此异常
  • class zifile.ZipFile:处理zip文件的类。用来打开、读写zip文件
  • class zipfile.ZipInfo([filename[, date_time]]):代表压缩文件中的一个被压缩的文件的类。ZipFile类的getinfo()和infolist()函数返回的是ZipInfo类的对象实例。通常,ZipInfo类的具体对象不需要我们创建,而是由函数返回得到。filename是zip文件的包含路径的完整文件名,date_time是一个包含了文件最新修改时间的有6个元素“年-月-日-时-分-秒”的元组(tuple),如(1999, 9, 11, 20, 11, 8)。
  • zipfile.is_zipfile(filename):基于文件的幻数(magic number,用来标记文件的格式,如rar格式文件的开头为Rar,zip文件开头为PK)判断文件filename是否是有效的zip文件,是则返回True,否则返回False。
  • zipfile.ZIP_STORED:代表未解压的压缩文件中的文件的数字常量。(The numeric constant for an uncompressed archive member.)
  • zipfile.ZIP_DEFLATED:代表通常压缩方法的数字常量。这个需要zlib模块的支持。目前还不支持其它的压缩方法。【deflate是一个压缩算法。它是无损压缩】

ZipFile类 #

ZipFile类用来处理zip文件,提供打开、解压缩等。ZipFile类的主要内容有:

class zipfile.ZipFile(file [,mode [,compression [,allowZip64] ] ])

ZipFile类构造函数,打开一个zip文件,并返回该zip文件的ZipFile对象。

  • file:要打开的zip文件的文件名,可以是一个普通的文件名(一个string),或者是一个类文件(file-like)的对象。
  • mode:文件打开方式。‘r’表示读取已存在的文件,‘w’表示截取(即存在则清空)并写一个新文件, ‘a’表示追加到一个已存在的文件后面(如果file指向的不是一个zip文件,那么将会创建一个新的zip文件,并且附加到file指向的文件,示例如下)。
#coding=utf-8
#author=JarvisChu

import zipfile

#创建zip文件,使用'a'追加模式,同时file指向一个已存在的非zip文件
zf = zipfile.ZipFile('flower.jpg','a',zipfile.ZIP_DEFLATED)

#创建一个文本文件 1.txt
f = open('1.txt','w')
f.write('This a simple text file')
f.close()

#将文本文件附加到flower中
zf.write('1.txt')

#关闭zip文件
zf.close()

使用 ‘a’ 模式打开了一张jpg图片,然后创建了一个1.txt文本文件并写入到压缩文件。运行上述脚本,则将包含1.txt的压缩文件附加到了flower.jpg图片文件中。此时,磁盘中直接打开flower.jpg则显示图片,如果改后缀名jpg为zip,则变为一个zip文件,打开后为包含了1.txt的压缩文件。

flower zip flower

这就是图片种子,原理就是将一个zip压缩文件附加到,或称为隐藏到一个图片文件中。在Windows系统中,可以另一种简单的制作方法:比如要将b.zip文件隐藏到a.jpg图片中,得到的图片种子命名为c.jpg,则打开cmd,切换到文件所在目录,输入下面一行命令即可

copy a.jpg /B + b.zip = c.jpg

c.jpg显示为a.jpg的图片,如果改后缀为zip,则变成了显示b.zip压缩文件。继续回到正文:

  • compression:当网往zip文件中写时使用的压缩算法,必须是ZIP_STORED或者ZIP_DEFLATED。如果该参数不是这两个可选值,则抛出RuntimeError异常。如果只为ZIP_DEFLATED,但是zlib模块不可用,则仍抛出RuntimeError异常。默认值为ZIP_STORED。如果allowZip64设为True,则当zip文件大于2GB时,会使用ZIP64扩展来创建zip文件。如果值为False(默认),当文件需要ZIP64扩展时,则会抛出异常。ZIP64扩展默认设置为无效,是因为Unix系统上zip和unzip命名不支持该扩展。

ZipFile.close() #

关闭zip压缩文件。在程序退出时,必须调用close函数,否则一些必须的记录不会被写到文件中。

ZipFile.getinfo(name) #

返回压缩文件中名为name的文件的ZipInfo对象。如果name文件不存在,则抛出KeyError异常

ZipFile.infolist() #

返回一个包含了压缩文件中所有文件各自对应的ZipInfo对象的列表。列表中的排列顺序和在实际压缩文件中的排列顺序相同。

ZipFile.namelist() #

返回一个包含了压缩文件中所有文件的名字的列表。

ZipFile.open(name [,mode [,pwd ] ]) #

解压压缩文件中一个文件得到类文件(file-like)对象。

  • name:压缩文件中的一个文件名或者是一个ZipInfo对象。
  • mode:必须是’r’、‘U’或者’rU’。默认为’r’。选择’U’或者’rU’会使得只读对象中的universal newline功能生效。
  • pwd:解压密码。对一个关闭的ZipFile调用open()会抛出RuntimeError异常。

注1:file-like对象是只读的,且提供了如下函数:read()、readline()、readlines()、iter()、next()

注2:open()、read()和extract()函数,都接受一个文件名或者一个ZipInfo对象。当zip文件中存在重名的文件时,你会喜欢用这个方法的。

ZipFile.extract(member [,path [,pwd]]) #

解压zip文件中的文件member到当前工作目录。文件的信息会尽可能准确的被解压出来。path指示解压到另一个目录。pwd是解压密码。

ZipFile.extractall([path [,members [,pwd]]]) #

解压所有文件到当前工作目录。path指示解压到另一个目录。pwd是解压密码。

#coding=utf-8
import zipfile
zf = zipfile.ZipFile('simple.zip','r',zipfile.ZIP_DEFLATED)#打开已存在的zip文件
zf.extractall()#解压到当前目录
#zf.extractall('..') #解压到上一级目录
#zf.extractall('C:/tmp')#解压到C:/tmp文件夹,文件夹不存在则创建
zf.close()[/python]

ZipFile.printdir()

以表格形式显示压缩文件中所有文件。

import zipfile
zf = zipfile.ZipFile('test.zip','r',zipfile.ZIP_DEFLATED)
zf.printdir()
zf.close()

结果如下dir1为文件夹:

File Name         Modified                      Size

1.txt             2014-01-20 19:04:32           23

2.txt             2014-01-20 19:04:32           23

dir1/             2014-01-20 19:06:50           0

dir1/11.txt       2014-01-20 19:06:26           0

dir1/12.txt       2014-01-20 19:06:26           0

ZipFile.setpassword(pwd) #

设置pwd为默认解压密码,用来解压加密的文件。

ZipFile.read(name [,pwd]) #

返回压缩文件中name文件的字节(bytes)。压缩文件必须是以read或者append模式打开。

  • name:文件名或ZipInfo对象
  • pwd:解压密码。如果指定了该参数,会覆盖sefpassword()中指定的默认解码密码。

对已经关闭的zip文件调用read()会产生一个RuntimeError的异常。

# -*- coding: utf-8 -*-
import zipfile
#———————————————-
# 解压文件示例

#打开压缩包
zf = zipfile.ZipFile('simple.zip','r')   #读取压缩包中的文件信息
for info in zf.infolist():
print info.filename,info.date_time,info.file_size
#输出: 1.txt (2014, 1, 2, 13, 16, 26) 23

#解压文件
for name in zf.namelist():  #文件名列表
#print name   #1.txt,2.txt…
f = file(name,'w')
f.write(zf.read(name)) #read函数读取文件内容
f.close()

#关闭压缩包
zf.close()

simple.zip中包含了1.txt,2.txt,3.txt,4.txt四个文件。zf.namelist()返回压缩文件中所有文件名列表。使用zf.read(name)读取文件中的所有字节,然后写入另一个文件则实现了解压。

ZipFile.testzip() #

读取压缩包中所有文件,并检查它们的CRC和文件头。返回第一个破损的文件的名字,或者None。对已关闭的ZipFile对象调用testzip()会抛出RuntimeError异常。

ZipFile.write(filename [,arcname [,compress_type]]]) #

将文件名为filename的文件写入到压缩文件中。arcname指示在压缩包中文件重命名的名字,不指定则和原文件名相同。compress_type指示压缩类型,如果指定了该参数则会覆盖创建时的compression参数。压缩文件必须以write或append模式打开,否则抛出RuntimeError异常。对已关闭的ZipFile调用该函数也会抛出RuntimeError异常。

注意:官方没有规定的文件名的编码。如果你有一个unicode类型(相对str类型而言的)的文件名,你必须先转换成字节字符串(byte strings,即str类型的有编码的字符串),然后再传递给write()

# -*- coding: utf-8 -*-
import zipfile

#———————————————-
# 压缩文件示例

txt = "This a simple text file"

#创建一个压缩文件
zf = zipfile.ZipFile('simple.zip','w',zipfile.ZIP_DEFLATED)

#创建4个txt文件,(1.txt,2.txt…),并添加到压缩文件
for i in range(1,5):
    filename = str(i)+".txt"
    f = file(filename,'w')
    f.write(txt)
    f.close()
    #添加到压缩文件
    zf.write(filename)

#关闭压缩文件
zf.close()

ZipFile.writestr(zinfo_or_arcname,bytes [,compress_type]) #

将字节串bytes写入到压缩包中。zinfo_or_arcname是压缩包中给定的文件名或者一个ZipInfo实例。如果是ZipInfo实例,至少要给出文件名、日期date和时间time。如果是文件名,date和time会被设置为当前的日期和时间。

注意:当将一个ZipInfo实例作为参数传入时,压缩函数使用ZipInfo实例中指定的compress_type。默认时,ZipInfo构造函数将这个参数设置w为ZIP_STORED.

ZipFile.debug #

ZipFile类的数据成员。指示debug输出时使用的等级。可以设置为0-3。0为默认,表示无输出,3表示the most output。

ZipFile.comment #

ZipFile类的数据成员。zip文件的注释信息。如果给使用’a’或’w’模式创建的ZipFile实例添加了注释,这个注释不能超过65535字节。超过这一大小的会被截断。【一个使用了comment的示例:PythonChallenge系列-P6 ZipFile】

PyZipFile类 #

PyZipFile的构造函数的参数与ZIpFile构造函数参数相同。PyZipFile类的实例比ZipFile对象实例多一个方法。

PyZipFile.writepy(pathname [,basename]) #

查找*.py文件并将其相关文件添加到压缩包中。如果存在*.pyo文件,则相关文件为*.pyo,否则为一个*.pyc文件,如果需要的话会编译该文件。如果pathname是一个以.py结尾的文件,则将相关文件(.pyo 或.pyc)添加到压缩包的最顶层,如果不是则抛出RuntimeError异常。如果pythname是一个目录,那么该目录下所有的pyc和pyo会被添加到压缩包最顶层,如果目录下有子目录,则递归添加。basename只用于内部使用。writepy()函数创建的文件名如下:

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

ZipInfo类 #

ZipInfo类的实例由ZipFile对象的getinfo()和infolist()函数返回。每一个对象值保存压缩包中一个文件的信息。ZipInfo对象有如下属性:

ZipInfo.filename #

压缩包中的该文件名

ZipInfo.date_time #

压缩包中该文件的最新修改时间,是一个包含6个元素的元组tuple。

Index	Value
0	Year (>=1980)
1	Month (one-based)
2	Day of Month (one-based)
3	Hours (zero-based)
4	Minutes (zero-based)
5	Seconds (zero-based)

注意:不支持早于1980年的时间。

ZipInfo.compress_type #

文件的压缩类型

ZipInfo.comment #

文件的注释

ZipInfo.extra #

附加数据。PKZIP Application Note给出了这个字符串中包含的结构体的一些注解。

ZipInfo.create_system #

创建zip文件的系统

ZipInfo.create_version #

创建zip文件的PKZIP版本

ZipInfo.extract_version #

解压压缩包需要的PKZIP版本号

ZipInfo.reserved #

必须是0

ZipInfo.bits #

zip文件的标识位

ZipInfo.volume #

文件头的卷号(volume number)

ZipInfo.internal_attr #

文件的内部属性

ZipInfo.external_attr #

文件的外部属性

ZipInfo.header_offset #

文件头部的偏移字节数

ZipInfo.CRC #

未压缩的文件的CRC-32

ZipInfo.compress_size #

压缩数据的大小

ZipInfo.file_size #

未压缩的文件的大小