我正在使用以下django / python代码将文件流式传输到浏览器:
wrapper = FileWrapper(file(path))
response = HttpResponse(wrapper, content_type='text/plain')
response['Content-Length'] = os.path.getsize(path)
return response
有没有办法在返回响应后删除文件?使用回调函数还是什么? 我可以创建一个cron删除所有tmp文件,但如果我可以流式传输文件并从同一请求中删除它们,那就更简洁了。
答案 0 :(得分:10)
您可以使用NamedTemporaryFile:
from django.core.files.temp import NamedTemporaryFile
def send_file(request):
newfile = NamedTemporaryFile(suffix='.txt')
# save your data to newfile.name
wrapper = FileWrapper(newfile)
response = HttpResponse(wrapper, content_type=mime_type)
response['Content-Disposition'] = 'attachment; filename=%s' % os.path.basename(modelfile.name)
response['Content-Length'] = os.path.getsize(modelfile.name)
return response
一旦驱逐新文件对象,就应该删除临时文件。
答案 1 :(得分:2)
大多数情况下,我们会使用定期的cron作业。
Django已经有一个cron工作来清理丢失的会话。你已经在运行了,对吧?
请参阅http://docs.djangoproject.com/en/dev/topics/http/sessions/#clearing-the-session-table
您希望在应用程序中使用另一个命令清除旧文件。
请参阅此http://docs.djangoproject.com/en/dev/howto/custom-management-commands/
另外,您可能不是真的从Django发送此文件。有时,您可以通过在Apache使用的目录中创建文件并重定向到URL来获得更好的性能,以便Apache可以为您提供该文件。有时这会更快。但是,它不能更好地处理清理工作。
答案 2 :(得分:2)
这只是使用常规的python方法(非常简单的例子):
# something generates a file at filepath
from subprocess import Popen
# open file
with open(filepath, "rb") as fid:
filedata = fid.read()
# remove the file
p = Popen("rm %s" % filepath, shell=True)
# make response
response = HttpResponse(filedata, content-type="text/plain")
return response
答案 3 :(得分:1)
一种方法是添加视图以删除此文件,并使用异步调用(XMLHttpRequest)从客户端调用它。这种情况的变体将涉及从客户端报告成功,以便服务器可以将此文件标记为删除并定期清理它。
答案 4 :(得分:1)
供将来参考: 我只是遇到了无法使用临时文件进行下载的情况。 但是我仍然需要在它之后删除它们;所以这就是我如何做到的(我真的不想依赖cron工作或芹菜或wossnames,它是一个非常小的系统,我希望它保持这种状态。)
def plug_cleaning_into_stream(stream, filename):
try:
closer = getattr(stream, 'close')
#define a new function that still uses the old one
def new_closer():
closer()
os.remove(filename)
#any cleaning you need added as well
#substitute it to the old close() function
setattr(stream, 'close', new_closer)
except:
raise
然后我只是将用于响应的流并插入其中。
def send_file(request, filename):
with io.open(filename, 'rb') as ready_file:
plug_cleaning_into_stream(ready_file, filename)
response = HttpResponse(ready_file.read(), content_type='application/force-download')
# here all the rest of the heards settings
# ...
return response
我知道这很快又脏,但确实有效。我怀疑对于每秒有数千个请求的服务器来说效率会很高,但这不是我的情况(每分钟最多几十个)。
编辑:忘了精确地说我正在处理下载期间无法容纳在内存中的非常大的文件。这就是我使用BufferedReader
(io.open()
下面的内容)的原因
答案 5 :(得分:0)
Python 3.7,Django 2.2.5
from tempfile import NamedTemporaryFile
from django.http import HttpResponse
with NamedTemporaryFile(suffix='.csv', mode='r+', encoding='utf8') as f:
f.write('\uFEFF') # BOM
f.write('sth you want')
# ref: https://docs.python.org/3/library/tempfile.html#examples
f.seek(0)
data=f.read()
response = HttpResponse(data, content_type="text/plain")
response['Content-Disposition'] = 'inline; filename=export.csv'