UploadFile 使用 Python 的 SpooledTemporaryFile,这是一个“存储在内存中的文件”,并且“一旦关闭就会被销毁”。有关这方面的更多信息,请查看this answer。
选项 1
要在途中解决问题(即,从 csv 文件读取而不使用从 contents = await file.read() 获得的文件内容),您可以将文件内容复制到 NamedTemporaryFile 中(再次检查 @987654324 @out 了解更多信息),然后使用它来迭代 csv 内容。下面是一个工作示例:
import uvicorn
from fastapi import FastAPI, File, UploadFile
from tempfile import NamedTemporaryFile
import os
import csv
app = FastAPI()
@app.post("/upload")
async def upload(file: UploadFile = File(...)):
contents = await file.read()
data = {}
file_copy = NamedTemporaryFile(delete=False)
try:
with file_copy as f: # The 'with' block ensures that the file closes and data are stored
f.write(contents);
with open(file_copy.name,'r', encoding='utf-8') as csvf:
csvReader = csv.DictReader(csvf)
for rows in csvReader:
key = rows['No']
data[key] = rows
finally:
file_copy.close() # Remember to close any file instances before removing the temp file
os.unlink(file_copy.name) # delete the file
return data
选项 2
或者,如前所述,更优雅的解决方案是使用上传文件的字节数据,从而避免将它们复制到新的临时文件中。将字节转换为字符串,然后将字符串对象加载到内存中的文本缓冲区(即StringIO)中,如here 所述,您可以将其传递给csv阅读器。下面的例子:
from fastapi import FastAPI, File, UploadFile
import csv
from io import StringIO
app = FastAPI()
@app.post("/upload")
async def upload(file: UploadFile = File(...)):
data = {}
contents = await file.read()
decoded = contents.decode()
buffer = StringIO(decoded)
csvReader = csv.DictReader(buffer)
for rows in csvReader:
key = rows['No']
data[key] = rows
buffer.close()
return data
选项 3
您还可以将上传文件中的字节写入BytesIO 流,然后您可以将其转换为 pandas 数据帧。接下来,使用to_dict() 方法,您可以将数据帧转换为字典并返回(默认情况下,FastAPI 将使用jsonable_encoder 转换为JSON 并返回JSONResponse)。
from fastapi import FastAPI, File, UploadFile
from io import BytesIO
import pandas as pd
app = FastAPI()
@app.post("/upload")
async def upload(file: UploadFile = File(...)):
contents = await file.read()
buffer = BytesIO(contents)
df = pd.read_csv(buffer)
buffer.close()
return df.to_dict(orient='records')