一、概述
打开客户端浏览器下载文件是比较常见的功能,那么后端是如何处理文件的呢?大体解决方法是后端会将文件处理成字节流并返回前端。那么在浏览器访问接口即可自动下载文件(此处是GET请求)。一篇关于文件流的文章值得了解
二、FastApi
2.1、下载:
from starlette.responses import StreamingResponse
from fastapi.response import FileResponse, Response
@app.get("/file")
def file():
# 提供一个下载成功后的文件名字
fileName = "xxx.jpg"
StreamingHttpResponse将文件内容进行流式传输,数据量大可以用这个方法
response = StreamingResponse(get_file_byte("xxx.jpg"), media_type="application/octet-stream")
# 在请求头进行配置
response = response.headers["Content-Disposition"] = "attachment; filename=%s"%fileName
return response
def get_file_byte(filename, chunk_size=512): # filename可以是文件,也可以是压缩包
with open(filename, "rb") as f:
while True:
content = f.read(chunk_size)
if content:
yield content
else:
break
三、django
3.1、下载
import os
from rest_framework import status
from django.http import HttpResponse
from rest_framework.response import Response
from django.utils.encoding import escape_uri_path
@action(methods=['GET'], detail=False)
def download_files(self, request, *args, **kwargs):
# fiName = request.query_params.get("file_name") # 辅助参数(?后)数据提取方式
fileName = request.data["file_name"] # 请求体body数据请求方式
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 项目根目录
file_path = os.path.join(base_dir, 'upload','images', fileName) # 下载文件的绝对路径
try:
# 提供一个下载成功后的文件名字
fileName = "xxx.zip"
response = HttpResponse(content = file_iterator(file_path)) # 字节流数据
response["content-type"] = "application/octet-stream"
response["Content-Disposition"] = "attachment; filename='{}'".format(escape_uri_path(fileName))
except:
return Response({"code":status.HTTP_400_BAD_REQUEST, "msg":"失败", "error": "Sorry but Not Found the File"})
return response
def file_iterator(file_path, chunk_size=512):
"""
文件生成器,防止文件过大,导致内存溢出
:param file_path: 文件绝对路径
:param chunk_size: 块大小
:return: 生成器
"""
with open(file_path, mode='rb') as f:
while True:
c = f.read(chunk_size)
if c:
yield c
else:
break
3.2、上传
import os
from rest_framework.response import Response
@action(methods=['POST'], detail=False)
def upload_file(self, request, *args, **kwargs):
try:
# 接收数据并处理
data = request.data
# 文件上传名字、文件上传路径、文件对象
name, path, fileObj= data["name"], data["path"], request.FILES["file"]
# 将传递的文件处理为文件流,进行保存
file = b''
for byteData in fileObj.chunks():
file += byteData
# 写入本地服务器
baseDir = os.path.dirname(os.path.abspath(__name__)); # 项目根目录
jpgDir = os.path.join(baseDir,'static','jpg'); # 文件保存路径
fileName = os.path.join(jpgDir, name);
with open(fileName, "wb") as f:
f.write(file)
except:
return Response({"code":status.HTTP_400_BAD_REQUEST, "msg":"失败", "error": "Uploading files failed. Procedure"})
return Response({"code":status.HTTP_200_OK, "msg":"成功")