【问题标题】:How do you save multitype/form data to a hard file in Python with FastAPI UploadFile?如何使用 FastAPI UploadFile 将多类型/表单数据保存到 Python 中的硬文件?
【发布时间】:2021-02-17 13:14:45
【问题描述】:

https://fastapi.tiangolo.com/tutorial/request-files/

*在下面解决*

我得到了一个适当大小的字节数组,但我不确定如何正确解析它以保存收到的表单文件数据。

几乎可以工作:

@app.post("/uploadfiles/")
async def create_files(files: List[bytes] = File(...)):
    out_file = open("files/1.txt", "w") # open for [w]riting as [b]inary
    out_file.write( str([(file) for file in files]))
    out_file.close()
    return {"file_sizes": [len(file) for file in files]}

脚本生成的文件不再是可读的 .png。我假设我使用的库不正确,但我不确定从哪个开始:HTMLResponse、FastAPI、multipart 或 List 可能?关于如何正确地将这些字节重新组合在一起的任何想法或文档?

编辑

休息一下,在回顾一下 FastAPI 文档后,我发现这个特殊的字节数据数组是多部分/表单数据数据(所以也许我会找到一个用于读取表单数据/图像的 python 库):

这是生成的数据的一个小示例(前约 100 个字符):

[b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x03\xe8\x00\x00\x01\xf4\x08\x06\x00\x00\x00\xae(\x07-\x00\x00\x01\x86iCCPICC profile\x00\x00(\x91}\x91=H\

我做到了!!!

秘诀在于 python 的原生字节识别库和操作顺序!!

@app.post("/uploadfiles/")
async def create_files(files: bytes = File(...)):
    out_file = open("files/1.jpg", "wb") # open for [w]riting as [b]inary
    out_file.write( bytes([(file) for file in files]))
    out_file.close()

在文件命名系统上仍有工作要做:) GL 大家!

编辑 2

由于下面的答案不起作用,我编写了一个文件名追加器:

@app.post("/uploadfiles/")

async def create_files(files: bytes = File(...)):
    with open('C:/data/sample.txt', 'r', encoding='utf-8') as g:
        data=g.readlines()

    for line in data:
        counter = int(line)
        with open('C:/data/sample.txt', 'w') as f:
            counter = counter + 1
            f.write(str(counter))

    out_file = open("files/" + str(counter) + ".jpg", "wb") # open for [w]riting as [b]inary
    out_file.write( bytes([(file) for file in files]))
    out_file.close()

感谢大家的帮助!快乐的黑客:^)

编辑 3

我被告知,我发布的方法与 FastAPI 结合使用可能是不正确的做法,因此为了更好地理解这一点,我发布了发布到后端的相关 javascript:

这是我的 reactjs 表单发布脚本中的相关代码:

 onSubmit = (e) => {
    e.preventDefault();

    const formData = new FormData();
if (this.state.images != null) {

    var form = document.getElementById("apiupform");
    document.getElementById("apiupform").hidden = true;
    Array.from(this.state.images).forEach((image) => {
      formData.append("files", image);
    });

    axios
      .post(`https://****.com/uploadfiles/`, formData, {
        headers: {
          "Content-Type": "multipart/form-data",
        },
      })

感谢大家对这项工作的帮助。当我发现改进时,我会更新它:)

【问题讨论】:

  • 您正在将多个文件写入一个文件,名为files/1.txt
  • 是的,我知道我开发的测试脚本的这个属性,它确实需要尽快改进。

标签: python file-upload byte fastapi http-upload


【解决方案1】:

你可以这样保存上传的文件,

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}'"}

或者,
使用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}'"}

Swagger 示例

【讨论】:

  • 恐怕我得到 python 错误:此脚本出现“无法处理的实体”。
  • 我认为这不会发生,因为这些示例将按原样工作。可能,您没有以正确的方式上传
  • 在我现场使用这个脚本时,它通过 https 和一个域名传递到后端。那么,也许这会在发布时改变一些属性?我将更新帖子以包含我的 js 表单代码。 ?‍♂️
  • 我不确定 js 客户端,但是,这个 应该在 FastAPI 的内置 swagger 中按原样工作(查看更新的屏幕截图) 和邮递员工具@JasonHokuLevien
【解决方案2】:

我会使用像 aiofiles 这样的异步库来进行文件操作。

由于您在事件循环中运行您的应用程序,因此文件写入操作将阻止您的应用程序的整个执行。

import aiofiles


@app.post("/uploadfiles/")
async def create_files(files: bytes = File(...)):
    async with aiofiles.open("files/1.jpg", "wb") as f:
        await f.write(bytes([(file) for file in files]))

【讨论】:

    【解决方案3】:

    这对我有用..

    @app.post("/fileUpload/")
    def fileUpload(ufile: UploadFile = File(...)):
        s = str(ufile.file.read(), 'utf-8')
    
        with open(ufile.filename, "w+") as buffer:
            buffer.write(s)
    

    【讨论】:

      猜你喜欢
      • 2020-12-14
      • 2022-08-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-27
      • 1970-01-01
      相关资源
      最近更新 更多