Flask 大文件下载

Flask 大文件下载,flask,download,Flask,Download,从Flask下载文件时发生内存错误。 文件大小约为100兆字节。 我怎样才能修好它 烧瓶下载代码 return send_from_directory(s_trash_path, s_zip_name, mimetype='zip', as_attachment=True) 错误代码 [2018-07-21 16:11:22,328] ERROR in app: Exception on /ec-fileupload/download/select [POST] Traceback (most

从Flask下载文件时发生内存错误。 文件大小约为100兆字节。 我怎样才能修好它

烧瓶下载代码

return send_from_directory(s_trash_path, s_zip_name, mimetype='zip', as_attachment=True)
错误代码

[2018-07-21 16:11:22,328] ERROR in app: Exception on /ec-fileupload/download/select [POST]
Traceback (most recent call last):
  File "/home/venv_ec_fileupload/lib/python3.6/site-packages/flask/app.py", line 1982, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/venv_ec_fileupload/lib/python3.6/site-packages/flask/app.py", line 1615, in full_dispatch_request
    return self.finalize_request(rv)
  File "/home/venv_ec_fileupload/lib/python3.6/site-packages/flask/app.py", line 1632, in finalize_request
    response = self.process_response(response)
  File "/home/venv_ec_fileupload/lib/python3.6/site-packages/flask/app.py", line 1856, in process_response
    response = handler(response)
  File "./app/__init__.py", line 170, in after_request
    s_data = resp.get_data()
  File "/home/venv_ec_fileupload/lib/python3.6/site-packages/werkzeug/wrappers.py", line 987, in get_data
    rv = b''.join(self.iter_encoded())
MemoryError

由于您的文件很大并且是动态生成的,我建议您不要使用
send\u from\u directory()
发送文件

查看有关如何流文件(发送小块数据而不是完整文件)的flask流文档:

上面的代码是关于如何使用flask流式传输csv文件的代码片段


但是,如果您的文件是静态的,那么Flask建议使用
nginx
进行部署

由于您的文件很大并且是动态生成的,我建议您不要使用
send\u from\u directory()
来发送文件

查看有关如何流文件(发送小块数据而不是完整文件)的flask流文档:

上面的代码是关于如何使用flask流式传输csv文件的代码片段


但是,如果您的文件是静态的,那么Flask建议使用
nginx
进行部署

如果您提供二进制文件,您不应该遍历行,因为它基本上只包含一个“行”,这意味着您仍然可以一次将整个文件加载到RAM中

读取大文件的唯一正确方法是通过块:

CHUNK\u SIZE=8192
def读取文件块(路径):
打开(路径“rb”)作为fd:
而1:
buf=fd.read(块大小)
如果buf:
产量单位
其他:
打破
然后,在该区块读取器上使用上下文调用
stream\u是安全的,例如,如果您提供视频文件:

@app.route(“/videos/”)
def SERVER_视频(名称):
fp=资源\路径/名称
如果fp.exists():
返回响应(
具有上下文的流(读取文件块(fp)),
标题={
“内容处置”:f“附件;文件名={name}”
}
)
其他:
提升执行未找到()

在引擎盖下,Flask响应过程获取每个区块(从生成器
读取\u文件\u区块(fp)
),并在加载下一个区块之前将其刷新到HTTP连接。刷新后,区块数据不再被引用,并被垃圾收集器清除,因此不会有多个区块同时留在RAM中。

如果提供二进制文件,则不应遍历行,因为它基本上只包含一个“行”,这意味着您仍然可以一次将整个文件加载到RAM中

读取大文件的唯一正确方法是通过块:

CHUNK\u SIZE=8192
def读取文件块(路径):
打开(路径“rb”)作为fd:
而1:
buf=fd.read(块大小)
如果buf:
产量单位
其他:
打破
然后,在该区块读取器上使用上下文调用
stream\u是安全的,例如,如果您提供视频文件:

@app.route(“/videos/”)
def SERVER_视频(名称):
fp=资源\路径/名称
如果fp.exists():
返回响应(
具有上下文的流(读取文件块(fp)),
标题={
“内容处置”:f“附件;文件名={name}”
}
)
其他:
提升执行未找到()

在引擎盖下,Flask响应过程获取每个区块(从生成器
读取\u文件\u区块(fp)
),并在加载下一个区块之前将其刷新到HTTP连接。刷新后,区块数据不再被引用,并被垃圾收集器清除,因此不会有许多区块同时留在RAM中。

感谢您的回答。我仍然有一个记忆错误。它正在发生。我的代码错了吗\n def generate():\n在r:yield str(line)response=response(generate(),mimetype='application/zip')response.headers['Content-Type']=“application/octet stream”response.headers['Content-Disposition']=“inline;filename=”+os.path.basename(s_path)返回responseThank以获取您的答案。我仍然有一个记忆错误。它正在发生。我的代码错了吗\n def generate():\n在r:yield str(line)response=response(generate(),mimetype='application/zip')response.headers['Content-Type']=“application/octet stream”response.headers['Content-Disposition']=“inline;filename=”+os.path.basename(s_路径)返回响应
from flask import Response

@app.route('/large.csv')
def generate_large_csv():
    def generate():
        for row in iter_all_rows():
            yield ','.join(row) + '\n'
    return Response(generate(), mimetype='text/csv')