如何在FastAPI中保存UploadFile [英] How to save UploadFile in FastAPI

查看:635
本文介绍了如何在FastAPI中保存UploadFile的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我通过POST接受文件.当我将其保存在本地时,可以使用file.read()读取内容,但是会显示通过file.name不正确的名称(16).当我尝试使用此名称查找它时,出现错误.可能是什么问题?

I accept the file via POST. When I save it locally, I can read the content using file.read (), but the name via file.name incorrect(16) is displayed. When I try to find it by this name, I get an error. What might be the problem?

我的代码:

  @router.post(
    path="/po/{id_po}/upload",
    response_model=schema.ContentUploadedResponse,
)
async def upload_file(
        id_po: int,
        background_tasks: BackgroundTasks,
        uploaded_file: UploadFile = File(...)):
    """pass"""
    uploaded_file.file.rollover()
    uploaded_file.file.flush()
    #shutil.copy(uploaded_file.file.name, f'/home/fyzzy/Desktop/api/{uploaded_file.filename}')
    background_tasks.add_task(s3_upload, uploaded_file=fp)
    return schema.ContentUploadedResponse()

推荐答案

背景

UploadFile 只是的包装 SpooledTemporaryFile ,可以作为 UploadFile.file 访问.

SpooledTemporaryFile()[...]函数与TemporaryFile()完全一样操作

TemporaryFile

给出>:

返回一个类似文件的对象,该对象可用作临时存储区.[..]它会在关闭后立即销毁(包括在垃圾回收对象时的隐式关闭).在Unix下,文件的目录条目要么根本不创建,要么在创建文件后立即删除.其他平台不支持此功能.您的代码不应依赖使用此功能创建的临时文件,该文件在文件系统中是否具有可见名称.

Return a file-like object that can be used as a temporary storage area. [..] It will be destroyed as soon as it is closed (including an implicit close when the object is garbage collected). Under Unix, the directory entry for the file is either not created at all or is removed immediately after the file is created. Other platforms do not support this; your code should not rely on a temporary file created using this function having or not having a visible name in the file system.

异步定义端点

您应使用 UploadFile的以下异步方法: write read seek close .它们在线程池中执行并异步等待.

async def endpoint

You should use the following async methods of UploadFile: write, read, seek and close. They are executed in a thread pool and awaited asynchronously.

要异步将文件写入磁盘,可以使用 aiofiles .示例:

For async writing files to disk you can use aiofiles. Example:

@app.post("/")
async def post_endpoint(in_file: UploadFile=File(...)):
    # ...
    async with aiofiles.open(out_file_path, 'wb') as out_file:
        content = await in_file.read()  # async read
        await out_file.write(content)  # async write

    return {"Result": "OK"}

或者以分块方式,以免将整个文件加载到内存中

Or in the chunked manner, so as not to load the entire file into memory:

@app.post("/")
async def post_endpoint(in_file: UploadFile=File(...)):
    # ...
    async with aiofiles.open(out_file_path, 'wb') as out_file:
        while content := await in_file.read(1024)  # async read chunk
            await out_file.write(content)  # async write chunk

    return {"Result": "OK"}

def 端点

此外,我想从主题(所有学分@dmontagu),使用 shutil.copyfileobj 和内部 UploadFile.file :

def endpoint

Also, I would like to cite several useful utility functions from this topic (all credits @dmontagu) using shutil.copyfileobj with internal UploadFile.file:

import shutil
from pathlib import Path
from tempfile import NamedTemporaryFile
from typing import Callable

from fastapi import UploadFile


def save_upload_file(upload_file: UploadFile, destination: Path) -> None:
    try:
        with destination.open("wb") as buffer:
            shutil.copyfileobj(upload_file.file, buffer)
    finally:
        upload_file.file.close()


def save_upload_file_tmp(upload_file: UploadFile) -> Path:
    try:
        suffix = Path(upload_file.filename).suffix
        with NamedTemporaryFile(delete=False, suffix=suffix) as tmp:
            shutil.copyfileobj(upload_file.file, tmp)
            tmp_path = Path(tmp.name)
    finally:
        upload_file.file.close()
    return tmp_path


def handle_upload_file(
    upload_file: UploadFile, handler: Callable[[Path], None]
) -> None:
    tmp_path = save_upload_file_tmp(upload_file)
    try:
        handler(tmp_path)  # Do something with the saved temp file
    finally:
        tmp_path.unlink()  # Delete the temp file

注意:您想在 def 端点内部使用上述功能,而不是 async def 端点,因为它们利用了阻塞API.

Note: you'd want to use the above functions inside of def endpoints, not async def, since they make use of blocking APIs.

这篇关于如何在FastAPI中保存UploadFile的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆