【问题标题】:Zip multiple directories and files in memory without storing zip on disk在内存中压缩多个目录和文件,而不在磁盘上存储 zip
【发布时间】: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 中添加一个文件夹,即使它是空的?

【问题讨论】:

    标签: python-3.x zip zipfile


    【解决方案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')
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-01-18
        • 1970-01-01
        • 1970-01-01
        • 2021-08-09
        • 2014-09-23
        • 1970-01-01
        相关资源
        最近更新 更多