我有一个管理一组文件的应用程序,但这些文件实际上存储在Rackspace的CloudFiles中,因为大多数文件将是~100GB。我正在使用Cloudfile的TempURL功能来允许单个文件,但有时,用户会想要下载一组文件。但是下载所有这些文件并生成本地 Zip 文件是不可能的,因为服务器只有 40GB 的磁盘空间。
从用户的角度来看,当您收到包含几张图片的电子邮件时,我想像 GMail 那样实现它:它为您提供了一个链接来下载包含所有图像的 Zip 文件,并且下载是即时的。
如何使用Python/Django实现这一点?我发现了 ZipStream,并且由于迭代器输出而看起来很有前途,但它仍然只接受文件路径作为参数,并且 writestr
方法需要一次获取所有文件数据(~100GB)。
从Python 3.5开始,可以创建大文件/文件夹的zip块流。您可以使用不可搜索的流。所以现在不需要使用ZipStream。在这里看到我的答案。
在这里活生生的例子:https://repl.it/@IvanErgunov/zipfilegenerator
如果您没有 filepath,但有字节块,则可以从示例中排除open(path, 'rb') as entry
,并将iter(lambda: entry.read(16384), b'')
替换为可迭代的字节。并手动准备 ZipInfo:
zinfo = ZipInfo(filename='any-name-of-your-non-existent-file', date_time=time.localtime(time.time())[:6])
zinfo.compress_type = zipfile.ZIP_STORED
# permissions:
if zinfo.filename[-1] == '/':
# directory
zinfo.external_attr = 0o40775 << 16 # drwxrwxr-x
zinfo.external_attr |= 0x10 # MS-DOS directory flag
else:
# file
zinfo.external_attr = 0o600 << 16 # ?rw-------
您还应该记住,zipfile 模块会写入其 zip 文件自身大小的块。因此,如果您发送一段 512 字节,则流只有在 zipfile 模块决定这样做时才会收到一段数据。这取决于压缩算法,但我认为这不是问题,因为 zipfile 模块会制作小块 <= 16384。
您可以使用 https://pypi.python.org/pypi/tubing。下面是一个使用 s3 的示例,您可以非常轻松地创建一个机架空间 clouldfile Source。创建客户编写器(而不是接收器。对象)将数据流式传输到其他位置,并自定义转换器来转换流。
from tubing.ext import s3
from tubing import pipes, sinks
output = s3.S3Source(bucket, key)
| pipes.Gunzip()
| pipes.Split(on=b'n')
| sinks.Objects()
print len(output)
看看这个 - 它是 Python 标准库的一部分:http://docs.python.org/3/library/zipfile.html#zipfile-objects
您可以为其提供打开的文件或类似文件的对象。