flask如何使模板返回大文件,又不消耗大量内存
当我们要往客户端发送大量的数据,比如一个大文件时,将它保存在内存中再一次性发到客户端开销很大。比较好的方式是使用流,本篇就要介绍怎么在Flask中通过流的方式来将响应内容发送给客户端。此外,我们还会演示如何实现文件的上传功能,以及如何获取上传后的文件。
响应流的生成
Flask响应流的实现原理就是通过Python的生成器,也就是大家所熟知的yield的表达式,将yield的内容直接发送到客户端。下面就是一个简单的实现:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
from flask import Flask, Response
app = Flask(__name__)
@app.route('/large.csv')
def generate_large_csv():
def generate():
for row in range(50000):
line = []
for col in range(500):
line.append(str(col))
if row % 1000 == 0:
print 'row: %d' % row
yield ','.join(line) + '\n'
return Response(generate(), mimetype='text/csv')
|
这段代码会生成一个5万行100M的csv文件,每一行会通过yield表达式分别发送给客户端。运行时你会发现文件行的生成与浏览器文件的下载是同时进行的,而不是文件全部生成完毕后再开始下载。这里我们用到了响应类”flask.Response”,它是”werkzeug.wrappers.Response”类的一个包装,它的初始化方法第一个参数就是我们定义的生成器函数,第二个参数指定了响应类型。
我们将上述方法应用到模板中,如果模板的内容很大,怎么采用流的方式呢?这里我们要自己写个流式渲染模板的方法。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
# 流式渲染模板
def stream_template(template_name, **context):
# 将app中的请求上下文内容更新至传入的上下文对象context,
# 这样确保请求上下文会传入即将被渲染的模板中
app.update_template_context(context)
# 获取Jinja2的模板对象
template = app.jinja_env.get_template(template_name)
# 获取流式渲染模板的生成器
generator = template.stream(context)
# 启用缓存,这样不会每一条都发送,而是缓存满了再发送
generator.enable_buffering(5)
return generator
|
这段代码的核心,就是通过”app.jinja_env”来访问Jinja2的Environment对象,这个我们在Jinja2系列中有介绍,然后调用Environment对象的”get_template()”方法来获得模板对象,再调用模板对象的”stream()”方法生成一个”StreamTemplate”的对象。这个对象实现了”__next__()”方法,可以作为一个生成器使用,如果你看了Jinja2的源码,你会发现模板对象的”stream()”方法的实现就是使用了yield表达式,所以原理同上例一样。另外,我们启用了缓存”enable_buffering()”来避免客户端发送过于频繁,其参数的默认值就是5。
现在我们就可以在视图方法中,采用”stream_template()”,而不是以前介绍的”render_template()”来渲染模板了:
|
1
2
3
4
5
|
@app.route('/stream.html')
def render_large_template():
file = open('server.log')
return Response(stream_template('stream-view.html',
logs=file.readlines()))
|
上例的代码会将本地的”server.log”日志文件内容传入模板,并以流的方式渲染在页面上。
另外注意,在生成器中是无法访问请求上下文的。不过Flask从版本0.9开始提供了”stream_with_context()”方法,它允许生成器在运行期间获取请求上下文:
|
1
2
3
4
5
6
7
8
9
|
from flask import request, stream_with_context
@app.route('/method')
def streamed_response():
def generate():
yield 'Request method is: '
yield request.method
yield '.'
return Response(stream_with_context(generate()))
|
因为我们初始化Response对象时调用了”stream_with_context()”方法,所以才能在yield表达式中访问request对象。
转载:
1、http://www.bjhee.com/flask-ad5.html
flask如何使模板返回大文件,又不消耗大量内存的更多相关文章
- python读取大文件的方法及mmap内存映射模块
python计算文件的行数和读取某一行内容的实现方法 :最简单的办法是把文件读入一个大的列表中,然后统计列表的长度.如果文件的路径是以参数的形式filepath传递的,那么只用一行代码就可以完成我们的 ...
- ASP.NET Core下载大文件的实现
当我们的ASP.NET Core网站需要支持下载大文件时,如果不做控制可能会导致用户在访问下载页面时发生无响应,使得浏览器崩溃.可以参考如下代码来避免这个问题. 关于此代码的几点说明: 将数据分成较小 ...
- 把大象装进冰箱:HTTP传输大文件的方法
上次我们谈到了HTTP报文里的div,知道了HTTP可以传输很多种类的数据,不仅是文本,也能传输图片,音频和视频. 早期互联网上传输的基本上都是只有几k大小的文本和小图片,现在的情况则大有不同.网 ...
- HttpApplication实战大文件上传 (第四篇)
一.Asp.net中的文件上传 在Asp.net 1.1中,文件在上传过程中将被全部保存在内存中,对于大文件来说,会造成内存空间的过度使用,可能会招致恶意攻击.为了解决这个问题,Asp.net在配置文 ...
- java处理excel-xlsx格式大文件的解决方案
1.第一次读取7M左右的ecxel文件,使用poi 库实现,参考了下面的博文. http://www.cnblogs.com/chenfool/p/3632642.html 使用上面的方法在 下面Wo ...
- python处理大文件——文件流处理
最近处理一份1000G+的大文件,直接loading进内存不可能,只能分片读取.文件介绍如下: 该文件是一份压缩的比对后文件(sam文件),该文件由很多细小的结构单元组成,一个结构如下: 两种方法: ...
- flask之jinja2模板语言
一.jinja2简单介绍 Jinja2是Python里一个被广泛应用的模版引擎,他的设计思想来源于Django的模板引擎,并扩展了其语法和一系列强大的功能.其中最显著的一个是增加了沙箱执行功能和可选的 ...
- PHP如何快速读取大文件
在PHP中,对于文件的读取时,最快捷的方式莫过于使用一些诸如file.file_get_contents之类的函数,简简单单的几行代码就能 很漂亮的完成我们所需要的功能.但当所操作的文件是一个比较大的 ...
- php操作大文件
看了http://hi.baidu.com/qiaoyuetian/item/76c51f0ce25030e4f45ba69e(php读取大文件详解),然后测试了里边的代码,发现一些错误, 总结,红色 ...
随机推荐
- ZJOI2018游记Round2
Day0 趁着空档还溜回班上了一节物理课:瓢泼之中在9:00赶往余姚,车程3h+-- 中饭在一家饭馆,味道海星. 晚上和ykh,chj,xzt溜去吃一鸣和烧烤.一鸣不错,烧烤的话我因为口腔溃疡没怎么吃 ...
- linux配置MySql表名不区分大小写
1.Linux下mysql安装完后是默认:区分表名的大小写,不区分列名的大小写:2.用root帐号登录后,在/etc/my.cnf中的[mysqld]后添加添加lower_case_table_nam ...
- Idea 搭建Maven--web项目(MVC)
小编最近正在学习使用MVC框架,在搭建Maven的项目过程中,遇到了很多问题,上网搜了很多材料才找到答案,为了小编以后查起来方便,也为了向广大小伙伴分享,写了这部片博文,敬我昨天一天的学习结果! 步骤 ...
- centos7中将python2.7.5版本升级到3.x版本
一.安装gcc源码编译器 yum -y install gcc gcc-c++ pcre-devel zlib-devel openssl-devel 二.下载python软件包 wget https ...
- CSS3-文本-text-shadow
一.text-shadow 语法: text-shadow : none | <length> none | [<shadow>, ] * <shadow> 或no ...
- 【转】怎么把本地项目和远程git仓库相连通
1. 打开在你的项目文件夹,输入下面的命令 git init 输完上面的命令,文件夹中会出现一个.git文件夹,如下图所示,其他的的文件也会出现蓝色小问号的标志 2. 添加所有文件 git add . ...
- teatime、
Python之路,Day7 - 面向对象编程进阶 本节内容: 面向对象高级语法部分 经典类vs新式类 静态方法.类方法.属性方法 类的特殊方法 反射 异常处理 Socket开发基础 作业:开发一个 ...
- Python的两个爬虫框架PySpider与Scrapy安装
Python的两个爬虫框架PySpider与Scrapy安装 win10安装pyspider: 最好以管理员身份运行CMD,不然可能会出现拒绝访问文件夹的情况! pyspider:pip instal ...
- (转)automaticallyAdjustsScrollViewInsets(个人认为iOS7中略坑爹的属性)
转自http://m.blog.csdn.net/blog/humingtao2013/27662093 automaticallyAdjustsScrollViewInsets(个人认为iOS7中略 ...
- HDU 4283 区间DP You Are the One
题解 我使用记忆化搜索写的.