最近使用Python/Django开发一个系统,暂且称之为A系统,卡在大文件下载上面,查询了django官方doc和stackoverflow上的很多资料,最终圆满解决此问题,如下为具体过程:
一 A系统中的文件下载
首先是在view中定义查询方法,在网站上点击查询按钮后,由后台生成相应的数据文件,并将文件名暂存cookie中;
然后在在view中定义下载方法,采用FileWaper的方式,将文件打包为object,并返回response:
参考链接:http://stackoverflow.com/questions/1156246/having-django-serve-downloadable-files
1 response = HttpResponse(mimetype='application/force-download') 2 response['Content-Disposition'] = 'attachment; filename=%s' % smart_str(file_name) 3 response['X-Sendfile'] = smart_str(path_to_file) 4 # It's usually a good idea to set the 'Content-Length' header too. 5 # You can also set any other required headers: Cache-Control, etc. 6 return response
二 遇到的问题与解决方法
在template中配置好相应的内容,点击查询按钮,查出结果,然后点击下载按钮,问题来了,下载出来一个空文件;随即又多方查找,最后试验到另一个有效的下载方法:
参考链接:https://djangosnippets.org/snippets/365/
1 import os, tempfile, zipfile 2 from django.http import HttpResponse 3 from django.core.servers.basehttp import FileWrapper 4 5 6 def send_file(request): 7 """ 8 Send a file through Django without loading the whole file into 9 memory at once. The FileWrapper will turn the file object into an 10 iterator for chunks of 8KB. 11 """ 12 filename = __file__ # Select your file here. 13 wrapper = FileWrapper(file(filename)) 14 response = HttpResponse(wrapper, content_type='text/plain') 15 response['Content-Length'] = os.path.getsize(filename) 16 return response 17 18 19 def send_zipfile(request): 20 """ 21 Create a ZIP file on disk and transmit it in chunks of 8KB, 22 without loading the whole file into memory. A similar approach can 23 be used for large dynamic PDF files. 24 """ 25 temp = tempfile.TemporaryFile() 26 archive = zipfile.ZipFile(temp, 'w', zipfile.ZIP_DEFLATED) 27 for index in range(10): 28 filename = __file__ # Select your files here. 29 archive.write(filename, 'file%d.txt' % index) 30 archive.close() 31 wrapper = FileWrapper(temp) 32 response = HttpResponse(wrapper, content_type='application/zip') 33 response['Content-Disposition'] = 'attachment; filename=test.zip' 34 response['Content-Length'] = temp.tell() 35 temp.seek(0) 36 return response
但又出问题了,有的时候可以正常下载,有的时候下载出来也是一个空文件。经过多个参数的调试,终于发现规律,小文件下载没问题,大文件下载下来就是空的,这可真是奇怪。
随后参考链接中的回复,将如下一行:
wrapper = FileWrapper(file(filename)) 修改为:
wrapper = FileWrapper(open(filename, 'rb'))
然后抱着试试看的态度,试了一下,没想到,it works!!!