0

我正在尝试通过首先将我的 CSV 文件上传到 Fastapi 来将其转换为 Json,但是当我尝试直接处理它(而不将其存储在某处)时,我得到了错误

错误:FileNotFoundError:[错误 2] 没有这样的文件或目录:“testdata.csv”

代码 :

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}```

4

3 回答 3

0

UploadFile 使用 Python 的SpooledTemporaryFile,一个“存储在内存中的文件”,并且“一旦关闭就会被销毁”。有关这方面的更多信息,请查看此答案。要在途中解决问题(即,从 csv 文件中读取而不使用可以从中获取的文件内容contents = await file.read()),您可以将文件内容复制到NamedTemporaryFile 中(再次查看此答案以获取更多信息),然后用它来遍历 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)  # unlink (remove) the file from the system's Temp folder
    
    return data
    

if __name__ == '__main__':
    uvicorn.run(app, host='127.0.0.1', port=8000, debug=True)

更新

或者,如前所述,一个更优雅的解决方案是使用现有文件的字节内容。字节数据按此处所述进行解码。请参见下面的示例:

import uvicorn
from fastapi import FastAPI, File, UploadFile
import os
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()
    csvf = StringIO(decoded)
    csvReader = csv.DictReader(csvf)
    for rows in csvReader:             
        key = rows['No']
        data[key] = rows  
    
    return data
    

if __name__ == '__main__':
    uvicorn.run(app, host='127.0.0.1', port=8000, debug=True)
于 2022-01-10T15:45:31.133 回答
0

你得到的原因Error : FileNotFoundError: [Error 2] No such file or directory : "testdata.csv"是因为你试图读取一个没有存储在本地的文件。

如果您想以这种方式读取文件,则应在继续之前保存上传的文件:

async def upload(uploaded_file: UploadFile = File(...)):
    # save csv to local dir
    csv_name = uploaded_file.filename
    csv_path = 'path_to/csv_dir/'
    file_path = os.path.join(csv_path, csv_name)
    with open(file_path, mode='wb+') as f:
        f.write(uploaded_file.file.read())

    # read csv and convert to json
    data = {}
    with open(file_path, mode='r', encoding='utf-8') as csvf:
        csvReader = csv.DictReader(csvf)
        for rows in csvReader:             
            key = rows['No']
            data[key] = rows    
    return {data}
于 2022-01-07T09:55:56.613 回答
0

fileasync 函数中的upload()已经打开,您可以直接从中获取字符,无需再次打开它。同样在 FastAPI 中,该类UploadFile实际上是从标准库派生的tempfile.SpooledTemporaryFile,不能通过指定临时文件的路径来访问。

例如,如果您使用 CPython 并file.filenameupload()类 Unix 系统中SpooledTemporaryFile读取存储的数据超过max_size) 并在访问时简单地返回文件描述符(在 Unix 中应该是一个数字)SpooledTemporaryFile.filename

于 2022-01-07T10:27:05.520 回答