现在位置: 首页 > FastAPI 教程 > 正文

FastAPI 文件上传

FastAPI 提供了 FileUploadFile 两种方式来处理文件上传,支持单独上传文件和表单与文件混合上传。


安装依赖

文件上传同样依赖 python-multipart

pip install python-multipart

使用 UploadFile

UploadFile 是推荐的方式,它提供了更丰富的文件信息访问接口:

实例

from fastapi import FastAPI, UploadFile

app = FastAPI()


@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
    # UploadFile 提供的属性和方法
    return {
        "filename": file.filename,          # 文件名
        "content_type": file.content_type,  # 文件 MIME 类型
        "size": file.size,                  # 文件大小(字节)
    }

UploadFile 的属性和方法:

属性/方法类型说明
filenamestr | None上传文件的原始文件名
content_typestr | None文件的 MIME 类型(如 image/png
fileSpooledTemporaryFile类似文件的对象,可读取文件内容
sizeint | None文件大小(字节)
read()方法读取文件内容为 bytes
write()方法向文件写入内容
seek()方法移动文件指针位置
close()方法关闭文件

UploadFile 使用"SpooledTemporaryFile"存储文件内容,文件较小时保存在内存中,文件较大时自动写入磁盘,因此比 bytes 更节省内存。


使用 File 接收文件内容

File 直接将文件内容读取为 bytes,适合小文件:

实例

from fastapi import FastAPI, File

app = FastAPI()


@app.post("/files/")
async def create_file(file: bytes = File()):
    # file 是文件的原始字节数据
    return {"file_size": len(file)}

FileUploadFile 的对比:

对比项FileUploadFile
数据类型bytes文件对象
内存使用整个文件加载到内存大文件自动写入磁盘
文件信息无(只有内容)有文件名、类型、大小
适用场景小文件大文件、需要文件信息的场景

可选文件上传

使用默认值 None 使文件上传变为可选:

实例

from fastapi import FastAPI, UploadFile

app = FastAPI()


@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile | None = None):
    if not file:
        return {"message": "没有上传文件"}
    return {"filename": file.filename}

多文件上传

使用列表接收多个文件:

实例

from fastapi import FastAPI, UploadFile

app = FastAPI()


@app.post("/uploadfiles/")
async def create_upload_files(files: list[UploadFile]):
    return {"filenames": [file.filename for file in files]}

表单与文件混合上传

可以在同一个路由中同时接收表单数据和文件:

实例

from fastapi import FastAPI, File, UploadFile, Form

app = FastAPI()


@app.post("/items/")
async def create_item(
    # 表单字段
    name: str = Form(...),
    description: str | None = Form(None),
    # 文件上传
    file: UploadFile | None = None,
):
    result = {"name": name, "description": description}
    if file:
        result["filename"] = file.filename
    return result

保存上传的文件

以下示例展示如何将上传的文件保存到磁盘:

实例

import shutil
from fastapi import FastAPI, UploadFile

app = FastAPI()


@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
    # 将上传的文件保存到指定路径
    with open(f"uploads/{file.filename}", "wb") as buffer:
        shutil.copyfileobj(file.file, buffer)
    return {"filename": file.filename, "message": "文件上传成功"}

实际项目中,上传文件时应注意:1) 校验文件类型和大小;2) 使用安全的文件名(避免路径遍历攻击);3) 限制上传目录的权限;4) 对于大文件使用流式处理而非一次性读取。


小结

  • 推荐使用 UploadFile,它更节省内存且提供丰富的文件信息
  • File 适合小文件场景,直接读取为 bytes
  • 使用 list[UploadFile] 接收多文件上传
  • 表单(Form)和文件(UploadFile)可以在同一路由中使用
  • 上传文件时注意安全:校验文件类型、使用安全文件名、限制大小