Flask 中使用 make_response 下载大文件

在Flask中,可以使用make_response函数来实现下载大文件的功能。具体怎么操作呢,以我具体示例来说,其实很简单。以下是一个简单的示例代码,演示如何在Flask应用中使用make_response来下载大文件:

1、问题背景

在使用 Flask 框架开发 web 应用程序时,如果需要提供大文件下载功能,可能会遇到内存溢出问题。以下代码展示了一个尝试下载大文件的示例:

python 复制代码
raw_bytes = ""
with open(file_path, 'rb') as r:
    for line in r:
        raw_bytes = raw_bytes + line
response = make_response(raw_bytes)
response.headers['Content-Type'] = "application/octet-stream"
response.headers['Content-Disposition'] = "inline; filename=" + file_name
return response

当文件较小时(小于 1GB),这段代码可以正常工作。但是,当文件较大时(大于 1GB),就会抛出 MemoryError 异常。这是因为将超过 2GB 的二进制数据存储在一个字符串中可能会导致内存不足。

2、解决方案

为了解决这个问题,可以使用流式传输的方式来下载大文件。流式传输允许将文件分块发送,这样就可以避免内存不足的问题。

2.1 使用 Flask 的 stream_with_context() 函数

Flask 提供了一个 stream_with_context() 函数,可以将一个生成器对象转换为一个 Response 对象。生成器对象可以逐块生成数据,这样就可以避免一次性将整个文件加载到内存中。

以下代码展示了一个使用 stream_with_context() 函数的示例:

python 复制代码
from flask import stream_with_context, Response

@app.route('/stream_data')
def stream_data():
    def generate():
        # create and return your data in small parts here
        for i in xrange(10000):
            yield str(i)

    return Response(stream_with_context(generate()))

在这个示例中,generate() 函数是一个生成器函数,它逐块生成数据。stream_with_context() 函数将这个生成器对象转换为一个 Response 对象,这样就可以将数据流式传输到客户端。

2.2 使用 Flask 的 send_from_directory() 函数

如果要下载的静态文件,可以使用 Flask 的 send_from_directory() 函数。这个函数可以将静态文件直接从文件系统中发送到客户端,这样就可以避免内存不足的问题。

以下代码展示了一个使用 send_from_directory() 函数的示例:

python 复制代码
from flask import send_from_directory

@app.route('/download_file')
def download_file():
    file_path = 'path/to/file.txt'
    return send_from_directory(os.path.dirname(file_path), os.path.basename(file_path))

在这个示例中,send_from_directory() 函数将文件 /path/to/file.txt 发送到客户端。

2.3 使用第三方库

也可以使用一些第三方库来实现大文件下载功能。例如,flask-large-file-downloader 库可以帮助你轻松下载大文件。

以下代码展示了一个使用 flask-large-file-downloader 库的示例:

python 复制代码
from flask_large_file_downloader import LargeFileDownloader

app = Flask(__name__)
app.secret_key = 'super secret key'

app.config['LARGE_FILE_DOWNLOADER_DIRECTORY'] = 'path/to/directory'
app.config['LARGE_FILE_DOWNLOADER_BUFFER_SIZE'] = 1024 * 1024

lf_downloader = LargeFileDownloader(app)

@app.route('/download_file')
def download_file():
    file_path = 'path/to/file.txt'
    return lf_downloader.send_file(file_path)

在这个示例中,lf_downloader.send_file() 函数将文件 /path/to/file.txt 发送到客户端。

通过设置适当的响应头信息,浏览器会提示用户下载文件。generate函数会以流式方式逐块读取大文件内容,避免一次性加载整个文件到内存中。

请确保替换代码中的path_to_your_large_file为你实际的大文件路径。这样,当访问/download_large_file路由时,Flask应用会开始下载指定的大文件。如果有更好得建议可以评论区留言讨论。

相关推荐
雪隐2 分钟前
个人电脑玩AI-09让5060 Ti给你打工——让 AI 读懂你的资料
人工智能·后端
小满zs27 分钟前
Go语言第一章(入门)
后端·go
用户67570498850238 分钟前
Kafka 太重?试试 NSQ:一个优雅到极致的消息队列
后端·go
铁皮饭盒1 小时前
S3已成为文件存储标准,阿里/腾讯/华为云都支持,Bun率先原生支持
前端·javascript·后端
洛卡卡了1 小时前
Claude Code Hook,当 CLAUDE.md 规则不生效时,我们还需要强制拦截机制
后端·agent·claude
用户6757049885021 小时前
RabbitMQ 太重,Kafka 太复杂?Go 开发者:Asynq分布式任务队列就刚刚好
后端·go
AlbertLuo1 小时前
CodeMirror使用: 编写一个在线编辑HTML、JS、CSS文件,网页的模板页面-初实现
后端
SamDeepThinking1 小时前
裁掉那个差程序员后,给你看团队里高手的代码:这个习惯,希望你有
java·后端·程序员
Oneslide2 小时前
windows 11远程桌面连Ubuntu GNOME 远程登录频繁断开
后端
vivo互联网技术2 小时前
从 10 分钟到 1 秒:ES 深度分页任意跳页的三轮优化实战
服务器·数据库·redis·elasticsearch·深度分页