Python zipfile 只借助内存进行压缩与解压缩

Python zipfile 模块压缩与解压缩通常是对物理磁盘文件进行操作,比如参照官方的例子,生成压缩文件的代码是

with zipfile.ZipFile('spam.zip', 'w') as myzip:
    myzip.write('eggs.txt')
    myzip.write('beef.txt')

这样就生成了一个包含两个文件的压缩包 spam.zip, 相当于命令 zip spam.zip egges.txt beef.txt 的效果。用  unzip -l spam.zip 命令就能看到其中的两个文件。相应的解压缩的代码如下

with zipfile.ZipFile('spam.zip', 'r') as myzip:
    print(myzip.filelist())  # 可获得压缩包中的文件列表信息
    myzip.extractall()

同样是把压缩包 spam.zip 解压缩文件到当前目录中,相当于命令 unzip spam.zip 的效果。

前面顺便也是熟悉一下 zipfile 模块的常见用法,但有时候我们可能从数据库中,从网络上收到的是字节数据,希望直接处理字节的压缩解压缩,而不借助于中间的磁盘文件,因为通过磁盘文件来处理必须进行善后处理以及可能的资源的竞争,在内存宽裕的情况下效率也是个问题。

在 Java 中处理内存数据经常用到的是 ByteArrayInputStreamByteArrayOutputStream,而在 Python 中承担相同角色的就是 io.BytesIO()。下面来看如何使用它在内存进行双向操作

通过内存生成压缩文件字节内容

本例放到压缩包中的内容是字节,生成的压缩包也是字节表现形式

只需调用 myzip.writestr(filename, original_content) 方法就行,数据可以是字符串或 bytes,filename 部分还可以有目录结构

不指定 zipfile.ZIP_DEFLATED 的话不会对数据进行压缩,只是存储。

上面产生的  zip_data 就是压缩包的字节内容,我们把 zip_data 字节数据保存到  spam.zip 压缩文件,然后用 unzip -l spam.zip 命令查看

如果解压一下,会看到目录结构与我们设想的一致,三个文件 eggs.txt, beef.txtveggs/picle.txt 中的内容分别是字符符 Here are eggs, I am beef, 和 pickles

解压缩 zip 字节内容为字节数据

现在我们直接使用上一步产生的 spam.zip 文件内容,首先假定输入为字节数据,然后窥探其中每一个条目的文件信息与内容

这里的代码使用到了递归一直罗列压缩包中的条目,压缩包中文件的内容可用 read_text()read_bytes() 分别读出为文本或字节。这是此代码执行后的输出

$ python tt.py
eggs.txt : Here are eggs
beef.txt : I am beef
veggs/pickle.txt : pickles

如果我们明确的知道(比如约定了)压缩包中不会有目录层次,则可不用递归来处理。

链接:

  1. Zipfile module for Python3.6: write to Bytes instead of Files for Odoo
  2. Python Zipfile

本文链接 https://yanbin.blog/python-zipfile-compress-decompress-in-memory/, 来自 隔叶黄莺 Yanbin Blog

[版权声明] Creative Commons License 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments