zipfile

zipfile

  zipfile 是 python 里用来做 zip 格式编码的压缩和解压缩的,由于是很常见的 zip 格式,所以这个模块使用频率也是比较高的,在这里对 zipfile 的使用方法做一些记录。即方便自己也方便别人。
  Python zipfile 模块用来做 zip 格式编码的压缩和解压缩的,要进行相关操作,首先需要实例化一个 ZipFile 对象。ZipFile 接受一个字符串格式压缩包名称作为它的必选参数,第二个参数为可选参数,表示打开模式,类似于文件操作,有r/w/a三种模式,分别代表读、写、添加,默认为r,即读模式。
  zipfile 里有两个非常重要的 class , 分别是 ZipFile 和 ZipInfo , 在绝大多数的情况下,我们只需要使用这两个 class 就可以了。 ZipFile 是主要的类,用来创建和读取 zip 文件而 ZipInfo 是存储的 zip 文件的每个文件的信息的。

基本操作

  比如要读取一个 Python zipfile 模块,这里假设 filename 是一个文件的路径:

import zipfile

z = zipfile.ZipFile(filename, 'r')  # 这里的第二个参数用r表示是读取zip文件,w是创建一个zip文件
for f in z.namelist():
    print(f)

  上面的代码是读取一个 zip 压缩包里所有文件的名字。z.namelist() 会返回压缩包内所有文件名的列表。
再看看下面一个:

import zipfile

z = zipfile.ZipFile(filename, 'r')
for i in z.infolist():
    print(i.file_size, i.header_offset)

  这里使用了 z.infolist() , 它返回的就是压缩包内所有文件的信息,就是一个 ZipInfo 的列表。一个 ZipInfo 对象中包含了压缩包内一个文件的信息,其中比较常用的是 filename , file_size , header_offset , 分别为文件名,文件大小,文件数据在压缩包中的偏移。其实之前的 z.namelist() 就是读取的 ZipInfo 中的 filename ,组成一个 list 返回的。
  从压缩包里解压缩出一个文件的方法是使用 ZipFile 的 read 方法:

import zipfile

z = zipfile.ZipFile(filename, 'r')
print(z.read(z.namelist()[0]))

  这样就读取出 z.namelist() 中的第一个文件,并且输出到屏幕,当然也可以把它存储到文件。下面是创建 zip 压缩包的方法,与读取的方法其实很类似的:

import zipfile, os

 z = zipfile.ZipFile(filename, 'w')  # 注意这里的第二个参数是w,这里的filename是压缩包的名字

  假设要把一个叫 testdir 中的文件全部添加到压缩包里(这里只添加一级子目录中的文件):

if os.path.isdir(testdir):
     for d in os.listdir(testdir):
         z.write(testdir+os.sep+d)
         z.close()   # close() 是必须调用的!

  上面的代码非常的简单。想想还有一个问题,如果我把一个 test/111.txt 添加到压缩包里之后我希望在包里它放到 test22/111.txt 怎么办呢?其实这个就是 Python ZipFile 模块的 write 方法中第二个参数的作用了。只需要这样调用:

z.write("test/111.txt", "test22/111.txt")

ZipFile 与 ZipInfo 的基本操作

  1. class zipfile.ZipFile(file[, mode[, compression[, allowZip64]]])
      创建一个 ZipFile 对象,表示一个 zip 文件。参数 file 表示文件的路径或类文件对象( file-like object );参数 mode 指示打开 zip 文件的模式,默认值为'r',表示读已经存在的zip文件,也可以为'w'或'a','w'表示新建一个zip文档或覆盖一个已经存在的zip文档。
import zipfile

f = zipfile.ZipFile(filename, 'r')  # 这里的第二个参数用r表示是读取zip文件,w或a是创建一个zip文件

for f_name in f.namelist():  # z.namelist() 会返回压缩包内所有文件名的列表。
    print(f_name)
# 上面的代码是读取一个 zip 压缩包里所有文件的名字。

  a 表示将数据附加到一个现存的 zip 文档中。参数 compression 表示在写 zip 文档时使用的压缩方法,它的值可以是 zipfile. ZIP_STORED 或 zipfile. ZIP_DEFLATED 。如果要操作的 zip 文件大小超过2G,应该将 allowZip64 设置为 True 。
  ZipFile还提供了如下常用的方法和属性:
    ZipFile.getinfo(name)  获取zip文档内指定文件的信息。返回一个zipfile.ZipInfo对象,它包括文件的详细信息。
    ZipFile.infolist()  获取zip文档内所有文件的信息,返回一个zipfile.ZipInfo的列表。
    ZipFile.namelist()  获取 zip 文档内所有文件的名称列表。
    ZipFile.extract(member[, path[, pwd]])  将 zip 文档内的指定文件解压到当前目录。参数 member 指定要解压的文件名称或对应的 ZipInfo 对象;参数 path 指定了解析文件保存的文件夹;参数 pwd 为解压密码。
  下面一个例子将保存在程序根目录下的 duoduo.zip 内的所有文件解压到 D:/Work 目录:

import zipfile, os

f = zipfile.ZipFile(os.path.join(os.getcwd(), 'duoduo.zip'))  # 拼接成一个路径
for file in f.namelist():
  f.extract(file, r'd:/Work')  # 在d:/Work中解压文件
f.close()

image
  上面是 os.getcwd 的用法。
    ZipFile.extractall([path[, members[, pwd]]])  解压 zip 文档中的所有文件到当前目录。参数 members 的默认值为 zip 文档内的所有文件名称列表,也可以自己设置,选择要解压的文件名称。
    ZipFile.printdir()  将zip文档内的信息打印到控制台上。
    ZipFile.setpassword(pwd)  设置zip文档的密码。
    ZipFile.read(name[, pwd])  获取zip文档内指定文件的二进制数据。下面的例子演示了read()的使用,zip文档内包括一个duoduo.txt的文本文件,使用read()方法读取其二进制数据,然后保存到D:/duoduo.txt。

import zipfile, os

zipFile = zipfile.ZipFile(os.path.join(os.getcwd(), 'duoduo.zip'))
data = zipFile.read('duoduo.txt')
# (lambda f, d: (f.write(d), f.close()))(open(r'd:/duoduo.txt', 'wb'), data)  # 一行语句就完成了写文件操作。仔细琢磨哦~_~
with open(r'd:/duoduo.txt','wb') as f:
    for d in data:
        f.write(d)
zipFile.close()

    ZipFile.write(filename[, arcname[, compress_type]])  将指定文件添加到 zip 文档中。filename 为文件路径,arcname 为添加到 zip 文档之后保存的名称, 参数 compress_type 表示压缩方法,它的值可以是 zipfile.ZIP_STORED 或 zipfile. ZIP_DEFLATED 。下面的例子演示了如何创建一个 zip 文档,并将文件 D:/test.doc 添加到压缩文档中。

import zipfile, os

zipFile = zipfile.ZipFile(r'D:/test.zip'), 'w')
zipFile.write(r'D:/test.doc', '保存的名字', zipfile.ZIP_DEFLATED)
zipFile.close()

    zipFile.writestr(zinfo_or_arcname, bytes)  writestr()支持将二进制数据直接写入到压缩文档。
2. Class ZipInfo
  ZipFile.getinfo(name)  方法返回的是一个ZipInfo对象,表示zip文档中相应文件的信息。它支持如下属性:

  ZipInfo.filename  获取文件名称。
  ZipInfo.date_time  获取文件最后修改时间。返回一个包含6个元素的元组:(年, 月, 日, 时, 分, 秒)
  ZipInfo.compress_type  压缩类型。
  ZipInfo.comment  文档说明。
  ZipInfo.extr  扩展项数据。
  ZipInfo.create_system  获取创建该zip文档的系统。
  ZipInfo.create_version  获取 创建zip文档的PKZIP版本。
  ZipInfo.extract_version  获取 解压zip文档所需的PKZIP版本。
  ZipInfo.reserved  预留字段,当前实现总是返回0。
  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  获取未压缩的文件大小。
  下面一个简单的例子说明这些属性的意思:

import zipfile, os

zipFile = zipfile.ZipFile(os.path.join(os.getcwd(), 'duoduo.zip'))
zipInfo = zipFile.getinfo('文件中的文件.txt')

print ('filename:', zipInfo.filename)  # 获取文件名称
print ('date_time:', zipInfo.date_time)  # 获取文件最后修改时间。返回一个包含6个元素的元组:(年, 月, 日, 时, 分, 秒)
print ('compress_type:', zipInfo.compress_type)  # 压缩类型
print ('comment:', zipInfo.comment)  # 文档说明
print ('extra:', zipInfo.extra)  # 扩展项数据
print ('create_system:', zipInfo.create_system)  # 获取创建该zip文档的系统。
print ('create_version:', zipInfo.create_version)  # 获取创建zip文档的PKZIP版本。
print ('extract_version:', zipInfo.extract_version)  # 获取解压zip文档所需的PKZIP版本。
print ('reversed:', zipInfo.reserved)  # 预留字段,当前实现总是返回0。
print ('flag_bits:', zipInfo.flag_bits)  # zip标志位。
print ('volume:', zipInfo.volume)  # 文件头的卷标。
print ('internal_attr:', zipInfo.internal_attr)  # 内部属性。
print ('external_attr:', zipInfo.external_attr)  # 外部属性。
print ('header_offset:', zipInfo.header_offset)  # 文件头偏移位。
print ('CRC:', zipInfo.CRC)  # 未压缩文件的CRC-32。
print ('compress_size:', zipInfo.compress_size)  # 获取压缩后的大小。
print ('file_size:', zipInfo.file_size)  # 获取未压缩的文件大小。

zipFile.close()

Python 使用内存 zipfile 对象在内存中打包文件示例

import zipfile
import StringIO


class InMemoryZip(object):
    def __init__(self):
        # Create the in-memory file-like object
        self.in_memory_zip = StringIO.StringIO()

    def append(self, filename_in_zip, file_contents):
        '''
	Appends a file with name filename_in_zip and contents of file_contents to the in-memory zip.
	'''
        # Get a handle to the in-memory zip in append mode
        zf = zipfile.ZipFile(self.in_memory_zip, "a", zipfile.ZIP_DEFLATED, False)

        # Write the file to the in-memory zip
        zf.writestr(filename_in_zip, file_contents)

        # Mark the files as having been created on Windows so that
        # Unix permissions are not inferred as 0000
        for zfile in zf.filelist:
            zfile.create_system = 0

        return self

    def read(self):
        '''
	Returns a string with the contents of the in-memory zip.
	'''
        self.in_memory_zip.seek(0)
        return self.in_memory_zip.read()

    def writetofile(self, filename):
        '''
	Writes the in-memory zip to a file.
	'''
        f = file(filename, "w")
        f.write(self.read())
        f.close()

if __name__ == "__main__":
    # Run a test
    imz = InMemoryZip()
    imz.append("test.txt", "Another test").append("test2.txt", "Still another")
    imz.writetofile("test.zip")

Python 读 zip 文件

  下面的代码给出了用Python读取zip文件,打印出压缩文件里面所有的文件,并读取压缩文件中的第一个文件。

import zipfile

z = zipfile.ZipFile("zipfile.zip", "r")

#打印zip文件中的文件列表
for filename in z.namelist():
    print('File:', filename)


first_file_name = z.namelist()[0]  # 读取zip文件中的第一个文件的名字
content = z.read(first_file_name)
print(first_file_name)
print(content)

Python 写/创建 zip 文件

  Python写Zip文件主要用到ZipFile的write函数。

import zipfile

z = zipfile.ZipFile('test.zip', 'w', zipfile.ZIP_DEFLATED)
z.write('test.html')
z.close( )

  在创建ZipFile实例的时候,有两点要注意:
    1. 要用'w'或'a'模式,用可写的方式打开zip文件。
    2. 压缩模式有ZIP_STORED 和 ZIP_DEFLATED,ZIP_STORED只是存储模式,不会对文件进行压缩,这个是默认值,如果你需要对文件进行压缩,必须使用ZIP_DEFLATED模式。

Python 破解 zip 加密文件的方法

  首先我们先来桌面创建一个文件:
image
  我们创建了一个名为 q.txt 的文件然后我们将它压缩,压缩的时候记得设置上密码。
image
image
  我这边将密码设置为123456。使用 Python 的 zipfile 的模块,编写 zip 文件口令破解机。需要用到 Zip File 类中的 extractall 方法。这个类和这个方法对我们编程破解有口令保护的 Zip 文件是很有用的。请注意 extractant() 方法用可选参数指定密码的方式。
  导入库后,用带有口令保护的 Zip 文件的文件名,实例化一个新的 Zipfile 类。要解压这个 Zip 文件,我们使用 extractall 方法,并在可选参数 pwd 上填入口令。
  创建一个.py文件,在根目录然后在将我们的压缩文件放入同目录里面,项目结构目录:
image
  我们.py文件的代码:

import zipfile

zipFile = zipfile.ZipFile("q.zip","r")  # 这里是我们的压缩文件
zipFile.extractall(pwd="123456")  # 这里是我们的密码

  这段代码其实就是拿着密码去解压我们刚刚压缩的文件,网上大多数教程都是这样写的,但是我这边使用python3.6就会发现运行的时候报错了:
image
  反正错误大概的意思就是 pwd 的接收的数据应该是bytes类型但是它得到的却是str类型的反正就是类型错了,那我们就将密码转换为bytes类型,我们的py文件的代码如下:

import zipfile

zipFile = zipfile.ZipFile("q.zip","r")
password = '123456'
zipFile.extractall(pwd=str.encode(password) )

  这时候我们再次运行项目
image
  这次没有报错
image
  我们可以看到在我们的项目根目录下多了一个文件就是我们之前压缩的那个文件。
  接下来我们继续改造,如果用一个错误密码执行这个脚本会发生什么情况?让我们在脚本中增加一些捕获和处理异常的代码,显示错误的信息。

import zipfile

zipFile = zipfile.ZipFile("q.zip","r")
try:
    password = '123s456'
    zipFile.extractall(pwd=str.encode(password))
except Exception as ex:
    print(ex)

  这时候我们的py文件代码,并且我们还将密码故意写错来测试一下,来看一下运行结果:
image
  在这里我们可以看到错误 信息,就是告诉我们密码错误。我们可以用因口令不正确而抛出的异常来测试我们的字典文件(接下来的 zidian.text )中是否有 Zip 文件的口令。实例化一个 ZipFile 类之后,我们打开字典文件,遍历并测试字典中的每个单词。如果 extractall() 的执行没有出错,则打印一条消息,输出正确的口令。但是,如果 extractall() 函数抛出了一个口令错误的异常,就忽略这个异常,并继续测试字典中的下一个口令。
  我们先创建一个zidian.text文件
image
  接下来我们在 zidian.text 文件中编写我们的密码字典,每一行一个密码,红色部分是我们的正确密码
image
  然后将我们的密码字典放入项目中
image
  接着我们继续修改我们的脚本

zipFile = zipfile.ZipFile("q.zip","r")

passFile = open('zidian.txt')  # 打开我们的字典表
for line in passFile.readlines():
    password = line.strip('\n')  # 读取每一行数据(每一个密码)
    try:
        zipFile.extractall(pwd=str.encode(password))
        print('=========密码是:'+password+'\n')
        exit(0)  # 如果密码正确退出程序
    except Exception as ex:
        pass  # 跳过

  接下来我们看一下运行结果
image
  这样我们就已经成功破解了 zip 文件的密码,到这里我们不难发现只要我们字典里面有密码我们就可以破解出来。
  我们继续将我们的项目优化一下:

import zipfile


def extractFile(zFile,password):
    try:
        zFile.extractall(pwd=str.encode(password))
        return password  # 如果成功返回密码
    except:
        return


def main():
    zFile = zipfile.ZipFile("q.zip","r")
    passFile = open('zidian.txt')  # 打开我们的字典表
    for line in passFile.readlines():
        password = line.strip('\n')  # 读取每一行数据(每一个密码)
        guess = extractFile(zFile,password)
        if (guess):
            print("=========密码是:"+password+"\n")
            exit(0)

if __name__=='__main__':
    main()

  这样就好多了。
  接下来再给大家贴一个生成全部六位数数字密码的代码:

f = open('zidian.txt','w')
for id in range(1000000):
    password = str(id).zfill(6) + '\n'
    f.write(password)
f.close()

image
  运行成功后我们可以看到再我们的 zidian.txt 已经生成好了从000000到999999都有了这样我们只要是6位数数字密码的 zip 文件我们都可以破解了。

参考链接
  python中zipfile模块实例化解析

posted @ 2021-04-26 19:01  AKA绒滑服贵  阅读(802)  评论(0编辑  收藏  举报