" name="sm-site-verification"/>
侧边栏壁纸
博主头像
PySuper博主等级

千里之行,始于足下

  • 累计撰写 203 篇文章
  • 累计创建 14 个标签
  • 累计收到 1 条评论

目 录CONTENT

文章目录

Django 打包zip下载文件 -- zipstream

PySuper
2020-08-14 / 0 评论 / 0 点赞 / 5 阅读 / 5796 字
温馨提示:
所有牛逼的人都有一段苦逼的岁月。 但是你只要像SB一样去坚持,终将牛逼!!! ✊✊✊

下载大文件: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("文件下载失败")
0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区