如何使用 FastAPI 下载大文件?

2025-02-08 08:52:00
admin
原创
53
摘要:问题描述:我正在尝试.tar.gz从 FastAPI 后端下载一个大文件 ()。在服务器端,我只需验证文件路径,然后使用Starlette.FileResponse返回整个文件 — 就像我在 StackOverflow 上的许多相关问题中看到的那样。服务器端:return FileResponse(path=...

问题描述:

我正在尝试.tar.gz从 FastAPI 后端下载一个大文件 ()。在服务器端,我只需验证文件路径,然后使用Starlette.FileResponse返回整个文件 — 就像我在 StackOverflow 上的许多相关问题中看到的那样。

服务器端:

return FileResponse(path=file_name, media_type='application/octet-stream', filename=file_name)

此后,我收到以下错误:

  File "/usr/local/lib/python3.10/dist-packages/fastapi/routing.py", line 149, in serialize_response
    return jsonable_encoder(response_content)
  File "/usr/local/lib/python3.10/dist-packages/fastapi/encoders.py", line 130, in jsonable_encoder
    return ENCODERS_BY_TYPE[type(obj)](obj)
  File "pydantic/json.py", line 52, in pydantic.json.lambda
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8b in position 1: invalid start byte

我也尝试使用StreamingResponse,但出现同样的错误。还有其他方法吗?

我的代码中StreamingResponse

@x.post("/download")
async def download(file_name=Body(), token: str | None = Header(default=None)):
    file_name = file_name["file_name"]
    # should be something like xx.tar
    def iterfile():
        with open(file_name,"rb") as f:
            yield from f
    return StreamingResponse(iterfile(),media_type='application/octet-stream')

好的,这是这个问题的更新。我发现错误不是发生在这个api上,而是api在执行这个转发请求。

@("/")
def f():
    req = requests.post(url ="/download")
    return req.content

如果我返回一个StreamingResponse带有.tar文件的文件,则可能导致编码问题。

使用请求时,请记住设置相同的媒体类型。这是media_type='application/octet-stream'。它有效!


解决方案 1:

如果您发现使用类文件对象yield from f时速度相当慢,例如:StreamingResponse

from fastapi import FastAPI
from fastapi.responses import StreamingResponse

some_file_path = 'large-video-file.mp4'
app = FastAPI()

@app.get('/')
def main():
    def iterfile():
        with open(some_file_path, mode='rb') as f:
            yield from f

    return StreamingResponse(iterfile(), media_type='video/mp4')

您可以创建一个生成器,使用指定的块大小分块读取文件;从而加快该过程。示例如下。

请注意,StreamingResponse可以使用async生成器或普通的生成器/迭代器来流式传输响应主体。如果您使用open()不支持async/ 的标准方法await,则必须使用 normal 声明生成器函数def。无论如何,FastAPI/Starlette 仍将异步工作,因为它将检查您传递的生成器是否是异步的(如源代码中所示),如果不是,它将使用 在单独的线程中运行生成器,iterate_in_threadpool然后等待。

Content-Disposition您可以在响应中设置标题(如此答案中所述,以及此处和此处)以指示内容是否预计显示inline浏览器中(如果您正在流式传输,例如.mp4视频,.mp3音频文件等),或者作为下载并本地保存的内容attachment使用指定的filename)。

至于media_type(也称为 MIME 类型),有两种主要的 MIME 类型(请参阅常见的 MIME 类型):

  • text/plain是文本文件的默认值。文本文件应易于阅读,且不得包含二进制数据。

  • application/octet-stream是所有其他情况的默认值。未知文件类型应使用此类型

对于带有扩展名的文件.tar,如您的问题所示,您还可以使用不同于 的子类型octet-streamx-tar。否则,如果文件类型未知,请坚持使用application/octet-stream。有关常见 MIME 类型的列表,请参阅上面链接的文档。

选项 1 - 使用普通发电机

from fastapi import FastAPI
from fastapi.responses import StreamingResponse

CHUNK_SIZE = 1024 * 1024  # = 1MB - adjust the chunk size as desired
some_file_path = 'large_file.tar'
app = FastAPI()

@app.get('/')
def main():
    def iterfile():
        with open(some_file_path, 'rb') as f:
            while chunk := f.read(CHUNK_SIZE):
                yield chunk

    headers = {'Content-Disposition': 'attachment; filename="large_file.tar"'}
    return StreamingResponse(iterfile(), headers=headers, media_type='application/x-tar')

选项 2 - 使用async生成器aiofiles

from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import aiofiles

CHUNK_SIZE = 1024 * 1024  # = 1MB - adjust the chunk size as desired
some_file_path = 'large_file.tar'
app = FastAPI()

@app.get('/')
async def main():
    async def iterfile():
       async with aiofiles.open(some_file_path, 'rb') as f:
            while chunk := await f.read(CHUNK_SIZE):
                yield chunk

    headers = {'Content-Disposition': 'attachment; filename="large_file.tar"'}
    return StreamingResponse(iterfile(), headers=headers, media_type='application/x-tar')

解决方案 2:

我会用来app.mount("/static", StaticFiles(directory="static"), name="static")挂载一个静态文件夹,并将这个大文件放入该文件夹,这样用户就可以直接下载这个大文件的链接。

这样,您就不需要代码来读取文件并将文件提供给用户。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用