Fyz*_*zys 9 python temporary-files python-asyncio fastapi
我通过 POST 接受该文件。本地保存时,可以使用file.read()读取内容,但是显示通过file.name不正确(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()
Run Code Online (Sandbox Code Playgroud)
JPG*_*JPG 19
您可以通过这种方式保存上传的文件,
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post("/upload-file/")
async def create_upload_file(uploaded_file: UploadFile = File(...)):
file_location = f"files/{uploaded_file.filename}"
with open(file_location, "wb+") as file_object:
file_object.write(uploaded_file.file.read())
return {"info": f"file '{uploaded_file.filename}' saved at '{file_location}'"}Run Code Online (Sandbox Code Playgroud)
您还可以使用该shutil.copyfileobj(...)方法(请参阅有关两者如何在幕后工作的详细答案)。
因此,作为替代方法,您可以使用以下代码编写类似的内容shutil.copyfileobj(...)来实现文件上传功能。
import shutil
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post("/upload-file/")
async def create_upload_file(uploaded_file: UploadFile = File(...)):
file_location = f"files/{uploaded_file.filename}"
with open(file_location, "wb+") as file_object:
shutil.copyfileobj(uploaded_file.file, file_object)
return {"info": f"file '{uploaded_file.filename}' saved at '{file_location}'"}Run Code Online (Sandbox Code Playgroud)
ale*_*ame 12
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"}
Run Code Online (Sandbox Code Playgroud)
或者以分块的方式,以免将整个文件加载到内存中:
@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"}
Run Code Online (Sandbox Code Playgroud)
def 端点另外,我想从这个主题中引用几个有用的实用函数(所有学分@dmontagu),使用shutil.copyfileobjwith 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
Run Code Online (Sandbox Code Playgroud)
注意:您希望在
def端点内使用上述函数,而不是async def,因为它们使用了阻塞 API。
| 归档时间: |
|
| 查看次数: |
9251 次 |
| 最近记录: |