在我正在处理的网络应用中,用户可以创建一个包含文件的文件夹的zip存档。这是代码:
files = torrent[0].files
zipfile = z.ZipFile(zipname, 'w')
output = ""
for f in files:
zipfile.write(settings.PYRAT_TRANSMISSION_DOWNLOAD_DIR + "/" + f.name, f.name)
downloadurl = settings.PYRAT_DOWNLOAD_BASE_URL + "/" + settings.PYRAT_ARCHIVE_DIR + "/" + filename
output = "Download <a href=\"" + downloadurl + "\">" + torrent_name + "</a>"
return HttpResponse(output)
但是,正在下载zip存档时,这会产生长时间等待(10秒以上)的恶劣副作用。有可能跳过这个吗?而不是将存档保存到文件,是否可以直接发送给用户?
我确实相信torrentflux提供了我正在谈论的这个令人兴奋的功能。能够压缩GB数据并在一秒钟内下载。
答案 0 :(得分:12)
答案 1 :(得分:9)
正如mandrake所说,HttpResponse的构造函数接受可迭代对象。
幸运的是,ZIP格式可以在单个传递中创建存档,中央目录记录位于文件的最末端:
(图片来自Wikipedia)
幸运的是,只要您只添加文件,zipfile
确实不会进行任何搜索。
这是我提出的代码。一些说明:
所以,这里是:
import zipfile
class ZipBuffer(object):
""" A file-like object for zipfile.ZipFile to write into. """
def __init__(self):
self.data = []
self.pos = 0
def write(self, data):
self.data.append(data)
self.pos += len(data)
def tell(self):
# zipfile calls this so we need it
return self.pos
def flush(self):
# zipfile calls this so we need it
pass
def get_and_clear(self):
result = self.data
self.data = []
return result
def generate_zipped_stream():
sink = ZipBuffer()
archive = zipfile.ZipFile(sink, "w")
for filename in ["file1.txt", "file2.txt"]:
archive.writestr(filename, "contents of file here")
for chunk in sink.get_and_clear():
yield chunk
archive.close()
# close() generates some more data, so we yield that too
for chunk in sink.get_and_clear():
yield chunk
def my_django_view(request):
response = HttpResponse(generate_zipped_stream(), mimetype="application/zip")
response['Content-Disposition'] = 'attachment; filename=archive.zip'
return response
答案 2 :(得分:5)
这是一个简单的Django视图函数,它将/tmp
中的任何可读文件拉上(作为示例)并返回zip文件。
from django.http import HttpResponse
import zipfile
import os
from cStringIO import StringIO # caveats for Python 3.0 apply
def somezip(request):
file = StringIO()
zf = zipfile.ZipFile(file, mode='w', compression=zipfile.ZIP_DEFLATED)
for fn in os.listdir("/tmp"):
path = os.path.join("/tmp", fn)
if os.path.isfile(path):
try:
zf.write(path)
except IOError:
pass
zf.close()
response = HttpResponse(file.getvalue(), mimetype="application/zip")
response['Content-Disposition'] = 'attachment; filename=yourfiles.zip'
return response
当然这种方法只有在zip文件可以方便地放入内存时才有效 - 如果没有,你必须使用磁盘文件(你试图避免使用)。在这种情况下,您只需将file = StringIO()
替换为file = open('/path/to/yourfiles.zip', 'wb')
,并将file.getvalue()
替换为代码以读取磁盘文件的内容。
答案 3 :(得分:2)
您使用的zip库是否允许输出到流。您可以直接流式传输给用户,而不是临时写入压缩文件,然后流式传输给用户。
答案 4 :(得分:0)
可以将迭代器传递给HttpResponse (see docs)的构造函数。这将允许您创建一个自定义迭代器,在请求时生成数据。但是,我不认为这将使用zip(您必须在创建时发送部分zip)。
我认为,正确的方法是在一个单独的过程中离线创建文件。然后,用户可以监视进度,然后在准备就绪时下载文件(可能通过使用上述迭代器方法)。这与上传文件并等待处理文件时youtube等网站类似。