php 导出数据到excel(缓冲区应用)
2016-04-21 15:15
549 查看
昨天写了个php 结合缓冲区读取excel数据并批量导入mysql,缓冲区可有可无,没有多大的影响,接下来介绍一下php导出数据到excel,这次采用缓冲区的方式,大家知道,php中,所有的输出都会用到缓冲区,缓冲区的左右就是协调告诉的cpu与相对缓慢的I/O操作。
why?为什么会出现这种问题呢,答案网上一堆,我就简单点说,原因是,php把输出都缓冲了,并且一直到程序执行完才全部输出出来,这样的结果,我可以调处n多的不足:
一,很多时候需要在输出时设置header头,比如我们写程序测试时,输出出来的东西应该是对我们友好可读的,这个时候就需要设置utf8等header头,平时我们都把header头写在程序的开头,这是因为header之前不允许出现echo 等操作,不过这个可以通过php缓冲区避免,比如在第一次echo
之间 开启ob_start(),这样就会正常显示了(但是坚决不推崇这种方法,这是严重浪费系统资源的行为);
二,现在输出的数据真的特别的少,但是如果数据足够多呢,多到echo 所有的数据需要执行1w秒呢,难道要分文件下载吗?
其实真的不用这样,php给了解决这个的办法,而且很友好,下面是本篇文章的重点
cms系统中有很多将需求就是要把mysql数据导出到excel中,实现下载操作,原理很简单,数据库查数据,设置header头,让浏览器知道这是一个下载附件的操作,从而实现下载。
但是,有个问题,数据量小的时候,什么情况都无所谓,比如上面所说的,在没有超出memory_limit时,php程序正常运行,下载也很流畅,但是如果索要请求的数据很多呢,超过限制了呢,这样的情况再手动设置ini_set('memory_limit',"XXXXM")吗,万一数据多到你都不知道呢,要知道,你可分配的内存是有限的,为了这样的程序去随便的设置这些也是一种华丽的浪费。下面一个小程序,大家可以下载下来测试:
,不过不用纠结这个,这只是一个测试的极端结果。
echo 'hello123'; sleep(10); echo '再一次输出hello123';按照正常的逻辑,程序的运行应该是先输出hello123.之后10秒之后再输出‘再一次输出hello123’;
why?为什么会出现这种问题呢,答案网上一堆,我就简单点说,原因是,php把输出都缓冲了,并且一直到程序执行完才全部输出出来,这样的结果,我可以调处n多的不足:
一,很多时候需要在输出时设置header头,比如我们写程序测试时,输出出来的东西应该是对我们友好可读的,这个时候就需要设置utf8等header头,平时我们都把header头写在程序的开头,这是因为header之前不允许出现echo 等操作,不过这个可以通过php缓冲区避免,比如在第一次echo
之间 开启ob_start(),这样就会正常显示了(但是坚决不推崇这种方法,这是严重浪费系统资源的行为);
二,现在输出的数据真的特别的少,但是如果数据足够多呢,多到echo 所有的数据需要执行1w秒呢,难道要分文件下载吗?
其实真的不用这样,php给了解决这个的办法,而且很友好,下面是本篇文章的重点
cms系统中有很多将需求就是要把mysql数据导出到excel中,实现下载操作,原理很简单,数据库查数据,设置header头,让浏览器知道这是一个下载附件的操作,从而实现下载。
但是,有个问题,数据量小的时候,什么情况都无所谓,比如上面所说的,在没有超出memory_limit时,php程序正常运行,下载也很流畅,但是如果索要请求的数据很多呢,超过限制了呢,这样的情况再手动设置ini_set('memory_limit',"XXXXM")吗,万一数据多到你都不知道呢,要知道,你可分配的内存是有限的,为了这样的程序去随便的设置这些也是一种华丽的浪费。下面一个小程序,大家可以下载下来测试:
set_time_limit(10); ob_end_clean();//在循环输出前,要关闭输出缓冲区 echo str_pad('',1024);//浏览器在接受输出一定长度内容之前不会显示缓冲输出,这个长度值 IE是256,火狐是1024 for($i=10;$i>0;$i--){ $a=str_repeat('hello',$i).'<br />'; echo $a; flush(); //刷新输出缓冲 sleep(1); }通过运行程序,可以看到,在浏览器中输出的数据是渐渐的输出的,那么,大家应该明白了,既然如此,是不是可以将这个嵌套到导出excel的程序中呢,答案是肯定的,而且这样做的话,相当于把数据拆分成n多的小块,每一块都不超出内存,而且每取出来一块就能实时导出来数据,这样的体验,无疑是最好的,下面贴出一个测试版的:
$ceshi=array(); for($j=1;$j<100;++$j){ for($i=1;$i<100;++$i){ $ceshi[]=array($j,$i); } } header("Content-Type: application/force-download"); header("Content-type:application/vnd.ms-excel"); header("Content-Disposition:attachment; filename=".date("YmdHis").".xls"); echo '<HTML xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">'."\n"; echo '<head><meta http-equiv="content-type" content="application/vnd.ms-excel; charset=utf-8"></head>'."\n"; echo "<body>"; echo "<table width='100%' border='1'>"; echo "<tr align='center'><td>\$j</td><td>\$i</td></tr>"; foreach($ceshi as $rs) { echo "<tr align='left'><td>".$rs[0]."</td><td>".$rs[1]."</td></tr>"; sleep(1);//模拟数据多造成的后果 } echo '</table></body></html>';上面的程序是可执行的测试程序,通过sleep(1)模拟数据过多造成的页面等待状态,而如果注释掉那一行,就会是我们经常遇到的业务环境了,可以想象,1w条数据模拟的后果是最少等待1w秒才会出现下载提示;
$ceshi=array(); for($j=1;$j<100;++$j){ for($i=1;$i<100;++$i){ $ceshi[]=array($j,$i); } } header("Content-Type: application/force-download"); header("Content-type:application/vnd.ms-excel"); header("Content-Disposition:attachment; filename=".date("YmdHis").".xls"); echo '<HTML xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">'."\n"; echo '<head><meta http-equiv="content-type" content="application/vnd.ms-excel; charset=utf-8"></head>'."\n"; echo "<body>"; echo "<table width='100%' border='1'>"; echo "<tr align='center'><td>\$j</td><td>\$i</td></tr>"; ob_end_flush(); foreach($ceshi as $rs) { echo "<tr align='left'><td>".$rs[0]."</td><td>".$rs[1]."</td></tr>"; flush(); sleep(1); } echo '</table></body></html>';通过开启缓冲区,没取到一次数据就直接输出到浏览器端,这样就会直接显示出下载框,当用户点击之后,就会实现下载,虽然模拟的结果也是差不多1w秒才会完成,不过这种情况是不会出现滴,因为还没到1w秒,就会超出php限定的120秒
,不过不用纠结这个,这只是一个测试的极端结果。
相关文章推荐
- 一个关于if else容易迷惑的问题
- MySQL中的integer 数据类型
- MySQL存储过程
- Android Manifest 用法
- Android学习笔记(二九):嵌入浏览器
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- PHP5.2.*防止Hash冲突拒绝服务攻击的Patch
- 深入理解PHP之匿名函数
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- mysql中int、bigint、smallint 和 tinyint的区别与长度
- mysql load data 导出、导入 csv
- source命令执行SQL脚本文件
- 使用Python生成Excel格式的图片
- JSP/PHP基于Ajax的分页功能实现
- MySQL创建用户及权限控制
- MySQL管理数据表
- linux下mysql添加用户