最近在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 HttpResponse
from wsgiref.util import FileWrapper
# generate the file
response = HttpResponse(FileWrapper(myfile.getvalue()), content_type='application/zip')
response['Content-Disposition'] = 'attachment; filename=myfile.zip'
return response
复制
复制
当然,以上的方式对付小文件下载还是ok,因为都是读入到内存中,但如果某个文件特别大,就不能使用这种方式,那就应该采用另外一种方式,下面就是展示一下,在Django中的大文件下载如何写代码实现。如果文件非常大时,最简单的办法就是使用静态文件服务器,比如Apache或者Nginx服务器来处理下载。不过有时候,我们需要对用户的权限做一下限定,或者不想向用户暴露文件的真实地址,或者这个大内容是临时生成的(比如临时将多个文件合并而成的),这时就不能使用静态文件服务器了。
我们在django view中,需要用StreamingHttpResponse这两个类。完整的代码如下:
复制
from django.http import StreamingHttpResponse
def 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()
复制
复制
文章转载自聊聊电商业务与技术,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。
评论
相关阅读
python中标识符的命名规则和命名规范
周同学带您玩AI
116次阅读
2025-04-21 10:34:44
[MYSQL] binlog校验
大大刺猬
66次阅读
2025-05-13 15:45:23
解决pyqt5 textbrowser控件超链接锚点问题
zayki
43次阅读
2025-04-27 16:58:59
python 实现消费者优先级队列
天翼云开发者社区
34次阅读
2025-04-25 11:08:21
优雅遍历和删除特定开头的key
陌殇流苏
30次阅读
2025-04-25 12:17:03
《深入剖析Python的生成器表达式与列表推导式:探寻代码背后的哲学与艺术》
程序员阿伟
29次阅读
2025-04-27 16:22:14
python中的常见数据类型
周同学带您玩AI
18次阅读
2025-04-21 10:34:43
[Python] 探索ibd2sql的性能优化之道, 从1分40秒优化到约1秒
大大刺猬
15次阅读
2025-05-15 21:18:15
python自动更新dns A记录
godba
14次阅读
2025-04-23 11:19:04
python中不同数据类型转换-布尔型
周同学带您玩AI
11次阅读
2025-04-22 10:12:05