在一个网络应用程序,我的工作上,用户可以创建一个zip archive的一个文件夹完整的文件。在这里在这里的代码:

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)

但这有一个讨厌的副作用的一个漫长的等待(10秒),同时zip是正在下载。是否有可能跳过这个吗?而不是保存归档文件,是否有可能直接发送给用户?

我相信,torrentflux提供这plugh功能我谈论。能够压缩GBs的数据,并下载它的内的第二个。

有帮助吗?

解决方案

检查此在Django

其他提示

正如 mandrake 所说,HttpResponse 的构造函数接受可迭代对象。

幸运的是,ZIP 格式可以一次性创建存档,中央目录记录位于文件的最末尾:

enter image description here

(图片来自 维基百科)

幸运的是, zipfile 只要您只添加文件,确实不会进行任何搜索。

这是我想出的代码。一些注意事项:

  • 我正在使用此代码来压缩一堆 JPEG 图片。无关紧要 压缩 他们,我只使用 ZIP 作为容器。
  • 内存使用量为 O(size_of_largest_file) 而不是 O(size_of_archive)。这对我来说已经足够了:许多相对较小的文件加起来可能会构成巨大的存档
  • 此代码未设置 Content-Length 标头,因此用户无法获得良好的进度指示。它 应该是可能的 如果所有文件的大小已知,则提前计算此值。
  • 像这样直接向用户提供 ZIP 意味着恢复下载将不起作用。

所以,这里是:

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

下面是该拉链向上(作为一个例子)的任何可读文件在/tmp并返回压缩文件的简单的Django视图函数。

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()读取磁盘文件的内容。

是否使用的是允许输出到一个流的zip库。你可以直接将信号传送给用户,而不是暂时写入一个zip文件,然后流给用户。

它能够通过一个迭代的构造的HttpResponse (参看文档).这将允许您可以创建一个自定义的迭代,产生的数据,因为它是被请求。但是我不认为,将工作与个拉链(你会发送的局部的拉链,因为它正在创建)。

适当的方式,我想,就是创建在文件离线,在一个单独的进程。然后,用户可以监测取得的进展,然后下载的文件时,它准备(可能通过采用的迭代方法上所述)。这将类似的什么网站youtube等时使用的上载文件,并等待它将处理。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top