在内存中压缩多个目录和文件,而不在磁盘上存储 zip

Posted

技术标签:

【中文标题】在内存中压缩多个目录和文件,而不在磁盘上存储 zip【英文标题】:Zip multiple directories and files in memory without storing zip on disk 【发布时间】:2020-09-25 11:28:48 【问题描述】:

我有一个 Web 应用程序,它应该将多个目录和文件组合成一个 ZIP 文件,然后将此 ZIP 文件发送给最终用户。然后最终用户会自动收到一个下载的 ZIP 文件。

这意味着我实际上不应该将 ZIP 存储在服务器磁盘上,而是可以在内存中生成它,以便立即传递它。我最初的计划是使用shutil.make_archive,但这会将 ZIP 文件存储在磁盘的某个位置。 make_archive 的第二个问题是它需要一个目录,但似乎不包含将多个目录组合成一个 ZIP 的逻辑。这是供参考的最小示例代码:

import shutil
zipper = shutil.make_archive('/tmp/test123', 'zip', 'foldera')

然后我开始研究zipfile,它非常强大,可用于递归地遍历目录和文件并将它们应用到 ZIP。 Jerr 对另一个主题的回答是一个很好的开始。 zipfile.ZipFile 的唯一问题似乎是如果不存储在磁盘上就不能 ZIP?现在的代码如下所示:

import os
import zipfile
import io

def zip_directory(path, ziph):
    # ziph is a zipfile handle
    for root, dirs, files in os.walk(path):
        for file in files:
            ziph.write(os.path.join(root, file),
                       os.path.relpath(os.path.join(root, file),
                                       os.path.join(path, '..')))


def zip_content(dir_list, zip_name):
    zipf = zipfile.ZipFile(zip_name, 'w', zipfile.ZIP_DEFLATED)
    for dir in dir_list:
        zip_directory(dir, zipf)
    zipf.close()

zip_content(['foldera', 'folderb'], 'test.zip')

我的文件夹结构如下:

foldera
├── test.txt
|── test2.txt
folderb
├── test.py
├── folderc
  ├── script.py

但是,问题在于此 ZIP 存储在磁盘上。我存储它没有任何用处,因为我必须每天生成数千个 ZIP,它会填满太多的存储空间。

有没有办法不存储 ZIP 并将输出转换为 BytesIOstr 或其他我可以在内存中使用并在完成后将其丢弃的类型? 我还注意到,如果您只有一个没有任何文件的文件夹,那么它也不会被添加到 ZIP 中(例如,文件夹 'folderd' 中没有任何文件)。是否可以在 ZIP 中添加一个文件夹,即使它是空的?

【问题讨论】:

【参考方案1】:

据我所知,如果不将 ZIP 存储在磁盘上,就无法创建 ZIP(除非您想出一些将其保存到内存的巧妙方法,但这会占用大量内存)。我注意到您提到每天生成数千个 ZIP 会填满您的存储设备,但您可以在将 ZIP 发送回用户后简单地删除它。虽然这会在您的服务器上创建一个文件,但它只是临时的,因此只要您在发送后删除它就不需要大量存储空间。

【讨论】:

【参考方案2】:

使用BytesIO

filestream=BytesIO()
with zipfile.ZipFile(filestream, mode='w', compression=zipfile.ZIP_DEFLATED) as zipf:
     for dir in dir_list:
          zip_directory(dir, zipf)

你没有问如何发送,但为了记录,我在我的烧瓶代码中发送的方式是:

    filestream.seek(0)
    return send_file(filestream, attachment_filename=attachment_filename, 
                      as_attachment=True, mimetype='application/zip')

【讨论】:

以上是关于在内存中压缩多个目录和文件,而不在磁盘上存储 zip的主要内容,如果未能解决你的问题,请参考以下文章

我如何在 Java 中压缩文件而不包含文件路径

如何在 Django 中压缩多个上传的文件,然后再将其保存到数据库?

如何在Android中压缩下载的图像并在需要时解压缩?

如何将所有选定的文件添加到一个文件夹中并在php中压缩

如何[递归]在PHP中压缩目录?

详谈linux中压缩