16

我需要创建一个临时文件来发送它,我已经尝试过:

# Create a temporary file --> I think it is ok (file not seen)
temporaryfile = NamedTemporaryFile(delete=False, dir=COMPRESSED_ROOT)

# The path to archive --> It's ok
root_dir = "something"

# Create a compressed file --> It bugs
data = open(f.write(make_archive(f.name, 'zip', root_dir))).read()

# Send the file --> Its ok
response = HttpResponse(data, mimetype='application/zip')
response['Content-Disposition'] = 'attachment; filename="%s"' % unicode(downloadedassignment.name + '.zip')
return response

我根本不知道这是否是好方法..

4

2 回答 2

31

实际上,我只需要做类似的事情,如果可能的话,我想完全避免文件 I/O。这是我想出的:

import tempfile
import zipfile

with tempfile.SpooledTemporaryFile() as tmp:
    with zipfile.ZipFile(tmp, 'w', zipfile.ZIP_DEFLATED) as archive:
        archive.writestr('something.txt', 'Some Content Here')

    # Reset file pointer
    tmp.seek(0)

    # Write file data to response
    return HttpResponse(tmp.read(), mimetype='application/x-zip-compressed')

它使用 aSpooledTemporaryFile因此它将保留在内存中,除非它超出内存限制。然后,我将此临时文件设置为ZipFile要使用的流。传递给writestr的文件名只是文件在存档中的文件名,它与服务器的文件系统没有任何关系。然后,我只需要在完成它的事情seek(0)后倒回文件指针()ZipFile并将其转储到响应中。

于 2012-08-15T14:48:26.697 回答
11

首先,你不需要创建一个NamedTemporaryFile来使用make_archivemake_archive您想要的只是要创建的文件的唯一文件名。

.write不返回文件名

专注于该错误:您假设的返回值f.write是您可以打开的文件名;只需寻找文件的开头并阅读:

f.write(make_archive(f.name, 'zip', root_dir))
f.seek(0)
data = f.read()

请注意,您需要清理您创建的临时文件(您设置delete=False):

import os
f.close()
os.unlink(f.name)

或者,只需省略delete关键字使其True再次默认为,然后仅关闭文件,无需取消链接。

那只是将存档文件名写入新文件..

您只是将新存档名称写入临时文件。你最好直接阅读档案:

data = open(make_archive(f.name, 'zip', root_dir), 'rb').read()

请注意,现在您的临时文件根本没有被写入。

做到这一点的最佳方法

避免完全创建一个NamedTemporaryFiletempfile.mkdtemp()改为使用生成一个临时目录来放置您的存档,然后清理它:

tmpdir = tempfile.mkdtemp()
try:
    tmparchive = os.path.join(tmpdir, 'archive')

    root_dir = "something"

    data = open(make_archive(tmparchive, 'zip', root_dir), 'rb').read()

finally:
    shutil.rmtree(tmpdir)
于 2012-08-15T10:29:25.373 回答