Python内存zip库


77

是否有一个Python库,可以在不使用实际磁盘文件的情况下操纵内存中的zip存档?

ZipFile库不允许您更新存档。唯一的方法似乎是将其提取到目录中,进行更改,然后从该目录中创建新的zip。我想修改没有磁盘访问权限的zip归档文件,因为我将下载它们,进行更改并再次上传它们,因此没有理由存储它们。

尽管几乎没有任何接口可以避免磁盘访问,但类似于Java的ZipInputStream / ZipOutputStream的方法可以解决问题。


在这篇文章中,我回答了同样的问题。stackoverflow.com/questions/60643857/...
昆滕擦玻璃

Answers:


90

根据Python文档

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

  Open a ZIP file, where file can be either a path to a file (a string) or a file-like object. 

因此,要打开内存中的文件,只需创建一个类似文件的对象(也许使用BytesIO)。

file_like_object = io.BytesIO(my_zip_data)
zipfile_ob = zipfile.ZipFile(file_like_object)

51

从《Python中的In-Memory Zip》一文

以下是我的一篇自2008年5月以来关于使用Python压缩内存的帖子,由于Posterous关闭,该帖子已重新发布。

我最近注意到,有一个付费组件可用于使用Python压缩内存中的zip文件。考虑到这应该是免费的,我将以下代码组合在一起。它仅经过了非常基本的测试,因此,如果有人发现任何错误,请告诉我,我将对其进行更新。

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")

有用的链接-这是如何以Jason的答案描述的方式使用ZipFile对象的一个​​很好的例子。谢谢
John B 2010年

没问题,很高兴您发现它有用。
贾斯汀·埃斯蒂尔

2
请注意在此处总结链接的内容(如果链接消失),您的回答也一样
Ivo Flipse 2013年

1
@IvoFlipse-好点。为了防万一,我将所有这些内容添加到了这篇文章中。
贾斯汀·埃斯蒂尔2013年

2
在Windows或Python 3.X上无法真正使用,请参阅我的答案以获取代码更新。
Anthon

42

PYTHON 3

import io
import zipfile

zip_buffer = io.BytesIO()
with zipfile.ZipFile(zip_buffer, "a", zipfile.ZIP_DEFLATED, False) as zip_file:
    for file_name, data in [('1.txt', io.BytesIO(b'111')), ('2.txt', io.BytesIO(b'222'))]:
        zip_file.writestr(file_name, data.getvalue())
with open('C:/1.zip', 'wb') as f:
    f.write(zip_buffer.getvalue())

1
链接到文档。data可以是字节或字符串,并且可以在Ubuntu和Python 3.6上完美运行
Edgar H

22

Ethier提供的示例存在几个问题,其中一些很严重:

  • 在Windows上无法处理真实数据。ZIP文件是二进制文件,其数据应始终以打开的文件“ wb”写入
  • 将ZIP文件附加到每个文件后,效率很低。它可以打开并保存为InMemoryZip属性
  • 该文档指出应明确关闭ZIP文件,但未在append函数中完成此操作(对于示例来说,它可能有效,因为zf超出范围并关闭了ZIP文件)
  • 每次附加文件时,都会为zipfile中的所有文件设置create_system标志,而不是每个文件仅设置一次。
  • 在Python <3上,cStringIO比StringIO效率更高
  • 在Python 3上不起作用(原始文章来自3.0版本之前,但到发布代码时3.1已有很长时间了)。

如果您安装了更新的版本 ruamel.std.zipfile(我是作者),。后

pip install ruamel.std.zipfile

或从此处包括该班级的代码,您可以执行以下操作:

import ruamel.std.zipfile as zipfile

# Run a test
zipfile.InMemoryZipFile()
imz.append("test.txt", "Another test").append("test2.txt", "Still another")
imz.writetofile("test.zip")  

您也可以使用 imz.data任何需要的位置。

您还可以使用该with语句,如果提供文件名,则将在离开该上下文时编写ZIP的内容:

with zipfile.InMemoryZipFile('test.zip') as imz:
    imz.append("test.txt", "Another test").append("test2.txt", "Still another")

由于延迟写入光盘,因此您实际上可以test.zip在该上下文中从旧版本中读取内容。


为什么不在python 2中使用io.BytesIO?
盒装

@boxed除了没有特别的原因,您应该检查2.7上的BytesIO是否使用更快的底层C实现,并且不是调用StringIO(而不是CStringIO)的Python唯一兼容层
Anthon

实际上,这至少应该包括您为实际回答问题而编写的任何代码的框架,而不是仅仅告诉人们安装模块。如果没有其他要求,请至少链接到该模块的主页。
SilverbackNet
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.