我正在尝试使用
UploadFile
中的 FastAPI
上传 mp4 视频文件。
但是,OpencCV 无法读取上传的格式(cv2
)。
这是我的终点:
from fastapi import FastAPI, File, UploadFile
from fastapi.responses import PlainTextResponse
@app.post("/video/test", response_class=PlainTextResponse)
async def detect_faces_in_video(video_file: UploadFile):
contents = await video_file.read()
print(type(video_file)) # <class 'starlette.datastructures.UploadFile'>
print(type(contents)) # <class 'bytes'>
return ""
OpenCV 无法读取这两种文件格式(即
bytes
和 UploadFile
)。
您正在尝试传递文件
contents
(bytes
) 或 UploadFile
对象;但是,VideoCapture()
接受视频 filename
、捕获设备或 IP 视频流。
UploadFile
基本上是一个 SpooledTemporaryFile
(类似 file-like 的对象),其操作类似于 TemporaryFile
。但是,它在文件系统中没有可见的名称。正如您提到的,在处理文件后您不会将文件保留在服务器上,您可以将文件内容复制到“在文件系统中具有可见名称,可用于打开文件”(使用 NamedTemporaryFile
属性),如此处和
此处所述。根据文档: 是否可以使用
name
再次打开文件,而
命名的临时文件仍然打开,因平台而异(它可以是
所以在 Unix 上使用; 不能在 Windows 上)。如果删除是
( 默认),文件一关闭就会被删除。name
因此,在 Windows 上,在实例化true
时,您需要将
delete
参数设置为
False
,完成后,您可以使用 NamedTemporaryFile
或 os.remove()
方法手动删除它。 下面给出了如何执行此操作的两个选项。 选项 1使用
os.unlink()
端点实现解决方案,而 选项 2 使用
def
端点(利用 async def
库)。有关aiofiles
和
def
之间的区别以及选项2中使用的async def
功能的更多详细信息,请查看这个答案和
这个答案。如果您希望用户上传无法放入内存的较大文件,请查看 this 和 this 答案,了解如何分块读取上传的视频文件。 选项 1 - 使用
run_in_threadpool
端点
def
选项 2 - 使用 from fastapi import FastAPI, File, UploadFile
from tempfile import NamedTemporaryFile
import os
@app.post("/video/detect-faces")
def detect_faces(file: UploadFile = File(...)):
temp = NamedTemporaryFile(delete=False)
try:
try:
contents = file.file.read()
with temp as f:
f.write(contents);
except Exception:
return {"message": "There was an error uploading the file"}
finally:
file.file.close()
res = process_video(temp.name) # Pass temp.name to VideoCapture()
except Exception:
return {"message": "There was an error processing the file"}
finally:
#temp.close() # the `with` statement above takes care of closing the file
os.remove(temp.name)
return res
端点
async def