python - 如何在 FastAPI 中保存 UploadFile
问题描述
我通过 POST 接受文件。当我保存在本地时,我可以使用file.read()读取内容,但是显示通过file.name wrong(16)的名称。当我尝试按此名称查找它时,出现错误。可能是什么问题?
我的代码:
@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 下,文件的目录条目要么根本不创建,要么在文件创建后立即删除。其他平台不支持;您的代码不应依赖于使用此函数创建的临时文件,该文件在文件系统中具有或不具有可见名称。
async def
端点
您应该使用以下异步方法:、、和UploadFile
。它们在线程池中执行并异步等待。write
read
seek
close
对于将文件异步写入磁盘,您可以使用aiofiles
. 例子:
@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"}
或者以分块的方式,以免将整个文件加载到内存中:
@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
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。
推荐阅读
- android - 任务“:flutter_twitter:verifyReleaseResources”执行失败
- reactjs - 如何从firebase数据库中的开始和结束索引中检索行
- python - 从json文件中提取数据时,如何为每个输入文件获取相应的输出文本文件。?
- vb.net - 如何检查 tabcontrol 页面中的空控件?
- php - 获取子页面 id wordpress
- ios - 如何使用 Swift 在静态表视图底部添加动态表视图?
- python - 打印列表的问题,这些列表会根据列表条目的数量自动编号
- reactjs - 子路由内部的 dispatch() 导致无限循环
- flutter - 颤动显示 3d 对象 flutter_3d_obj
- android - 如何使用 Koin 对 MVVM 进行单元测试?