近来接到一个需求,经由过程挑选的时间段导出对应的用户接见日记到excel中, 由于用户量较大,常常会有导出50万加数据的状况。类别:PHP教程 / 日期:2019-12-01 / 浏览:200 / 评论:0
而经常运用的PHPexcel包须要把一切数据拿到后才生成excel, 在面临生成超大数据量的excel文件时这显然是会形成内存溢出的,所以斟酌运用让PHP边写入输出流边让浏览器下载的情势来完成需求。
我们经由过程以下的体式格局写入PHP输出流
$fp = fopen('php://output', 'a'); fputs($fp, 'strings'); .... .... fclose($fp)
php://output是一个可写的输出流,许可顺序像操纵文件一样将输出写入到输出流中,PHP会把输出流中的内容发送给web服务器并返回给提议要求的浏览器
别的由于excel数据是从数据库里逐渐读出然后写入输出流的所以须要将PHP的执行时间设长一点(默许30秒)set_time_limit(0)不对PHP执行时间做限定。
注:
以下代码只是说明生成大数据量EXCEL的思绪和步骤,并且在去掉项目营业代码后顺序有语法错误不能拿来直接运转,请依据本身的需求添补对应的营业代码!
/** * 文章接见日记 * 下载的日记文件一般很大, 所以先设置csv相干的Header头, 然后翻开 * PHP output流, 渐进式的往output流中写入数据, 写到一定量后将体系缓冲冲洗到相应中 * 防止缓冲溢出 */ public function articleAccessLog($timeStart, $timeEnd) { set_time_limit(0); $columns = [ '文章ID', '文章题目', ...... ]; $csvFileName = '用户日记' . $timeStart .'_'. $timeEnd . '.xlsx'; //设置好通知浏览器要下载excel文件的headers header('Content-Description: File Transfer'); header('Content-Type: application/vnd.ms-excel'); header('Content-Disposition: attachment; filename="'. $fileName .'"'); header('Expires: 0'); header('Cache-Control: must-revalidate'); header('Pragma: public'); $fp = fopen('php://output', 'a');//翻开output流 mb_convert_variables('GBK', 'UTF-8', $columns); fputcsv($fp, $columns);//将数据花样化为CSV花样并写入到output流中 $accessNum = '1000000'//从数据库猎取总量,假设是一百万 $perSize = 1000;//每次查询的条数 $pages = ceil($accessNum / $perSize); $lastId = 0; for($i = 1; $i <= $pages; $i++) { $accessLog = $logService->getArticleAccessLog($timeStart, $timeEnd, $lastId, $perSize); foreach($accessLog as $access) { $rowData = [ ......//每一行的数据 ]; mb_convert_variables('GBK', 'UTF-8', $rowData); fputcsv($fp, $rowData); $lastId = $access->id; } unset($accessLog);//开释变量的内存 //革新输出缓冲到浏览器 ob_flush(); flush();//必需同时运用 ob_flush() 和flush() 函数来革新输出缓冲。 } fclose($fp); exit(); }
好了, 实在很简单,就是用逐渐写入输出流并发送到浏览器让浏览器去逐渐下载全部文件,由于是逐渐写入的没法猎取文件的团体size所以就没办法经由过程设置header("Content-Length: $size");在下载前通知浏览器这个文件有多大了。不过不影响团体的效果这里的中心问题是处理大文件的及时生成和下载。
更新: 说一下我数据库查询这里的思绪,由于逐渐写入EXCEL的数据实际上来自Mysql的分页查询,人人晓得其语法是LIMIT offset, num 不过跟着offset越来越大Mysql在每次分页查询时须要跳过的行数就越多,这会严重影响Mysql查询的效力(包含MongoDB如许的NoSQL也是不发起skip掉多条来取效果集),所以我采纳LastId的体式格局来做分页查询。
相似下面的语句:
SELECT columns FROM `table_name` WHERE `created_at` >= 'time range start' AND `created_at` <= 'time range end' AND `id` < LastId ORDER BY `id` DESC LIMIT num
以上就是PHP及时生成并下载超大数据量的EXCEL文件的细致内容,更多请关注ki4网别的相干文章!