vlambda博客
学习文章列表

聊点Python:在Django中利用zipfile,StringIO等库生成下载的文件​

最近在django中要用到文件下载的功能,通过查找,发现以下几种方式,就收集在一起,供日后方便查找。

第一种方式:创建一个临时文件。可以节省了大量的内存。当你有多个或两个用户并发时,你会发现节省内存是非常非常重要的。

你可以写入一个StringIO(from io import StringIO)对象。


 
>>> import zipfile>>> import StringIO>>> buffer= StringIO.StringIO()>>> z= zipfile.ZipFile( buffer, "w" )>>> z.write( "idletest" )>>> z.close()>>> len(buffer.getvalue())


第二种方式,将文件打包成一个文件,下载的方式,需要设置Content-Disposition

 
from django.http import HttpResponsefrom wsgiref.util import FileWrapper
# generate the fileresponse = HttpResponse(FileWrapper(myfile.getvalue()), content_type='application/zip')response['Content-Disposition'] = 'attachment; filename=myfile.zip'return response


我们在django view中,需要用StreamingHttpResponse这两个类。完整的代码如下:

 
from django.http import StreamingHttpResponsedef big_file_download(request): # do something... def file_iterator(file_name, chunk_size=512): with open(file_name) as f: while True: c = f.read(chunk_size) if c: yield c else: break
the_file_name = "big_file.pdf" response = StreamingHttpResponse(file_iterator(the_file_name)) response['Content-Type'] = 'application/octet-stream' response['Content-Disposition'] = 'attachment;filename="{0}"'.format(the_file_name) return response


另外,给大家介绍一种使用zipstream库实现下载的功能,直接上代码,如下


class ZipUtilities(object): """ 打包文件成zip格式的工具类
使用方式
>>> utilities = ZipUtilities() >>> for file_obj in file_objs: >>> tmp_dl_path = os.path.join(path_to, filename) >>> utilities.to_zip(tmp_dl_path, filename) >>> utilities.close() >>> response = StreamingHttpResponse(utilities.zip_file, content_type='application/zip') >>> response['Content-Disposition'] = 'attachment;filename="{0}"'.format("下载.zip") """ zip_file = None
def __init__(self): self.zip_file = zipstream.ZipFile(mode='w', compression=zipstream.ZIP_DEFLATED)
def to_zip(self, file, name): if os.path.isfile(file): self.zip_file.write(file, arcname=os.path.basename(file)) else: self.add_folder_to_zip(file, name)
def add_folder_to_zip(self, folder, name): for file in os.listdir(folder): full_path = os.path.join(folder, file) if os.path.isfile(full_path): self.zip_file.write(full_path, arcname=os.path.join(name, os.path.basename(full_path))) elif os.path.isdir(full_path): self.add_folder_to_zip(full_path, os.path.join(name, os.path.basename(full_path)))
def close(self): if self.zip_file: self.zip_file.close()