下载大文件:Django 上传 / 下载 大文件
DjangoWeb 下载
django中实现下载功能的方法还是比较多,当我们使用视图函数的时候:
项目需求
需求分析
- 单个下载文件
- 打包下载多个文件
实现逻辑
- 对于不同的请求,分开处理
- 单个文件:
/download/?id=1&type=img
- 打包文件:
/download/id=1&type=all
代码实现
压缩文件
1. zipstream
import os
import zipstream
class ZipUtilities(object):
"""
将文件或者文件夹打包成ZIP格式的文件,然后下载,在后台可以通过response完成下载
"""
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()
2. zipfile
import zipfile
from io import StringIO
class MemoryZipFile(object):
def __init__(self):
# 创建内存文件
self._memory_zip = StringIO()
def append_file(self, filename_in_zip, local_file_full_path):
"""
description:写文件内容到zip
注意这里的第二个参数是本地磁盘文件的全路径:
windows: c:/demo/1.jpg
linux: /usr/local/test/1.jpg
"""
zf = zipfile.ZipFile(self._memory_zip, "a", zipfile.ZIP_DEFLATED, False)
zf.write(local_file_full_path, filename_in_zip)
for zfile in zf.filelist: zfile.create_system = 0
return self
def read(self):
"""
description: 读取zip文件内容
"""
self._memory_zip.seek(0)
return self._memory_zip.read()
下载文件
这里是使用
第一种(zipstream)
方式返回数据的
def download(request):
"""
从前端接受请求
==> 使用内存读取的方式
==> 完成单个数据下载,或者是多个文件打包下载
"""
file_id = request.GET.get("id", None)
download_type = request.GET.get("type", None)
file = A.objects.filter(id=file_id).first()
if file:
if download_type == "all":
# 通过内存的方式打包下载文件
utilities = zip_file.ZipUtilities()
folder_path = re.findall(r'(.*/).*', file.img)[0]
folder_name = re.findall(r'.*/A/(.*)/.*', file.img)[0]
utilities.add_folder_to_zip(folder_path, folder_name)
# utilities.close() # TODO: 这里关闭内存的话,数据没法返回
response = StreamingHttpResponse(
utilities.zip_file,
content_type='application/zip'
)
response['Content-Disposition'] = \
'attachment;filename="{0}.zip"'.format(folder_name)
return response
else:
file_path = getattr(file, download_type)
file_name = re.findall(r'.*/(.*)', file_path)[0]
def file_iterator(file_path, chunk_size=512):
with open(file_path, mode='rb') as f:
while True:
count = f.read(chunk_size)
if count:
yield count
else:
break
try:
response = StreamingHttpResponse(file_iterator(file_path))
response['Content-Type'] = 'application/octet-stream'
response['Content-Disposition'] = \
'attachment;filename="%s"' % (urlquote(file_name))
except:
return HttpResponse("Sorry but Not Found the File")
return response
return HttpResponse("文件下载失败")
评论区