• 216.面试题上传下载大文件django


    import os
    
    from pathlib import Path
    from django.http import HttpResponse, StreamingHttpResponse
    
    from tcp_client.settings import BASE_DIR
    
    DEFAULT_DIR_PATH = Path(BASE_DIR).joinpath("libs")
    MAX_SIZE = 1024 * 1024 * 2
    
    
    # 自定义异常
    class MyException(Exception):
        def __init__(self, code=1000, msg="ok"):
            self.code = code
            self.msg = msg
    
    
    class UploadFileException(MyException):
        pass
    
    
    class DownloadFileException(MyException):
        pass
    
    
    class FileNotExistsException(MyException):
        pass
    
    
    class FileOverMaxSizeException(MyException):
        pass
    
    
    # 自定装饰器, 处理异常以及日志
    def wrapper(func):
        def inner(*args):
            try:
                ret = func(*args)
            except MyException as e:
                ret = HttpResponse(e.msg)
            except Exception:
                import traceback
                ret = HttpResponse(traceback.format_exc())
            return ret
        return inner
    
    
    @wrapper
    def upload_file(request):
        """
        上传文件
        :param request.files: 文件参数
        :return: ret
        """
        files = request.FILES.getlist("files")
        if not files: raise UploadFileException(1001, "文件参数不能为空")
        for file in files:
            file_path = DEFAULT_DIR_PATH.joinpath(file.name)
            if not file_path.parent.exists():
                os.mkdir(file_path.parent)
            with open(file_path, "wb+") as f:
                for chunk in file.chunks():  # 每次写入一块, 节省内存
                    f.write(chunk)
        ret = "ok"
        return HttpResponse(ret)
    
    
    @wrapper
    def download_file(request):
        """
        下载文件
        :param request.filename: 文件名称
        :return: ret
        """
        file_name = request.POST.get("filename")
    
        if not file_name: raise DownloadFileException(1001, "文件名称不能为空")
        file_path = DEFAULT_DIR_PATH.joinpath(file_name)
        if not file_path.exists(): raise FileNotExistsException(1001, "文件不存在")
        # if os.path.getsize(file_path) > MAX_SIZE: raise FileOverMaxSizeException(1001, "文件过大")
    
        # 使用生成器, 每次读取固定字节大小文件
        def file_iterator(file_path, chunk_size=1024):
            with open(file_path, "rb") as f:
                while True:
                    c = f.read(chunk_size)
                    if c:
                        yield c
                    else:
                        break
        # django 自带的StreamingHttpResponse可以支持迭代器协议处理流文件
        ret = StreamingHttpResponse(file_iterator(file_path))
        # 将Content-Type设置为application/octet-stream流模式
        ret["Content-Type"] = "application/octet-stream"
        # Content-Disposition设置为attachment;filename={}, 浏览器会自动将保存到filename的文件中
        ret["Content-Disposition"] = "attachment;filename={}".format(file_name)
        return ret
    

    问题回顾:

    1. 项目中经常是写好之后复制粘贴, 面试中很难回想起来
    2. 大文件下载, 直接没太遇到过, 一般都是大文件上传, 没有想到django有自带的straem处理模式
      参考:
      https://blog.csdn.net/Zjack_understands/article/details/81368476
  • 相关阅读:
    go channel select如何屏蔽已关闭通道
    go err
    在OneNote中快速插入当前日期和时间
    如何查看Isilon节点的硬件信息?
    一个可用来记录Isilon各个节点的CPU,网络,磁盘性能的命令
    Linux中如何查看文件夹的大小
    如何同步两台Linux机器的时间?
    Linux中的硬链接(hard link)和符号连接(symbolic link)
    在Cygwin里,如何进入到C盘?
    Remote Desktop Session中如何触发Ctrl+Alt+Delete?
  • 原文地址:https://www.cnblogs.com/liuzhanghao/p/16000694.html
Copyright © 2020-2023  润新知