我尝试上传我的.csv
文件到我的FastAPI服务器,然后将其转换为JSON并返回给客户端。但是,当我尝试直接处理它(不将其存储在某个地方)时,我得到了以下错误:
Error : FileNotFoundError: [Error 2] No such file or directory : "testdata.csv"
这是我的FastAPI代码:
async def upload(file: UploadFile = File(...)):
data = {}
with open(file.filename,encoding='utf-8') as csvf:
csvReader = csv.DictReader(csvf)
for rows in csvReader:
key = rows['No']
data[key] = rows
return {data}```
3条答案
按热度按时间pprl5pva1#
下面给出了如何将上传的
.csv
文件转换为JSON的各种选项。下面的示例中使用了以下.csv
示例文件。数据.csv
选项1
csv.DictReader()
方法也可以接受文件对象作为file
参数。(要了解更多信息,请查看this answer).您可以通过UploadFile
对象的.file
属性访问它.但是,由于FastAPI/Starlette以bytes
模式打开文件,如果你直接将它传递给csv.DictReader()
方法,你会得到一个错误,即_csv.Error: iterator should return strings, not bytes
。因此,你可以使用codecs.iterdecode()
(如this answer中所建议的),它使用一个增量解码器对 iterator 提供的输入进行迭代解码(在本例中是从bytes
到str
)。示例:输出
如果您想返回字典的
list
,您可以使用下面的代码。因为下面的代码要求file
在返回结果时为open
,从而阻止服务器正确关闭文件(通过调用file.file.close()
)当它完成时,可以使用BackgroundTasks
(它运行 after 返回一个响应)关闭文件:输出
选项2
另一个解决方案是读取上传文件的字节数据-使用
contents = file.file.read()
(对于async
的读/写,请参见this answer)-然后将字节转换为字符串,最后将它们加载到内存中的文本缓冲区(即StringIO
),如前面提到的here,它可以传递给csv.DictReader()
。选项3
要以自己的方式解决这个问题(即,使用文件路径读取csv文件,而不是像前面所述的那样直接使用文件内容或类似文件的对象),可以将文件内容复制到
NamedTemporaryFile
中,它与UploadFile
提供的SpooledTemporaryFile
不同,“在文件系统中有一个可见的名称”,“可以用来打开文件”(同样,请查看this answer以了解更多信息)。下面是一个工作示例:选项4
还可以将上传文件中的字节写入BytesIO流,然后将其转换为Pandas DataFrame。(如this answer中所述),您可以将 Dataframe 转换为字典并返回它-FastAPI在后台使用
jsonable_encoder
将其转换为JSON兼容的数据,最后,序列化数据并返回一个JSONResponse
(有关详细信息,请参阅this answer)。或者,您可以使用to_json()
方法并直接返回一个Response
,如选项1(更新2)here中所述。注意:如果文件太大,占用了所有内存和/或处理和/或返回结果花费了太多时间,请查看this answer、this answer和this answer.
q7solyqu2#
您之所以会得到
Error : FileNotFoundError: [Error 2] No such file or directory : "testdata.csv"
,是因为您尝试读取的文件不是本地存储的。如果要以这种方式读取文件,则应在继续操作之前保存上载的文件:
t30tvxxf3#
异步函数
upload()
中的file
已经打开,可以直接从中取字符,不需要再打开。同样在FastAPI中,类UploadFile
实际上是从标准库tempfile.SpooledTemporaryFile
派生的,不能通过指定临时文件的路径来访问。例如,如果使用CPython并在类Unix系统的
upload()
中读取file.filename
的值,它将返回一个数字而不是格式良好的路径,因为类SpooledTemporaryFile
的任何示例都将创建文件描述符(在当前存储的数据超过max_size
时的某个点),并在访问SpooledTemporaryFile.filename
时简单地返回文件描述符(在Unix中应为数字