在内存中压缩多个目录和文件,而不在磁盘上存储 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 并将输出转换为 BytesIO
、str
或其他我可以在内存中使用并在完成后将其丢弃的类型?
我还注意到,如果您只有一个没有任何文件的文件夹,那么它也不会被添加到 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的主要内容,如果未能解决你的问题,请参考以下文章