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
posted @   楠海  阅读(193)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
点击右上角即可分享
微信分享提示