您的位置 首页 php

PHPexcle大数据量导出

最近接到一个需求,通过选择的时间段导出对应的订单数据到excel中, 由于数据量较大,经常会有导出500K+数据的情况。平常的导出用的PHPexcle,将数据一次性读取到内存中再一次性写入文件,而在面对生成超大数据量的excel文件时这显然是会造成内存溢出的。

这时就需要循环批量写入excle导出。

过程中可能遇到的问题:

1.超时:Maximum execution time of 30 seconds exceeded

解决:在文件开头加上 set_time_limit(0);即php执行时间不受限制。

2.内存溢出:Allowed memory size of 134217728 bytes exhausted (tried to allocate 20480 bytes)

解决:

2.1 可在ini文件设置;设置memory_limit,将内存设置加大,

2.2 在执行代码前加上 ini_set(“memory_limit”, “1024M”);

2.3 每次读取的数据量减少,增加循环的次数;

3.导出的excle数字过长展示成科学计数

解决:

3.1 在要写入的数字数据,后面加个 “\t”;

3.2 或是数字转换为字符串格式

上代码(生成excle链接导出数据):

​public function downBigExcle()

​ ​ ​{

​ ​ ​ set_time_limit(0);

​ ​ ​ #自定义导出地址+文件名

​ ​ ​

​ ​ ​ $pathName = time().’. CSV ‘;

​ ​ ​

​ ​ ​ #计算要导出总数据条数

​ ​ ​

​ ​ ​ $totalNums = Db::table(‘t_excle’)->count(‘id’);

​ ​ ​

​ ​ ​ #设置表头标题

​ ​ ​

​ ​ ​ $headerTitleArr = [‘xx’,’xxx’];

​ ​ ​

​ ​ ​ #CSV的Excel支持GBK编码,一定要转换,否则乱码

​ ​ ​

​ ​ ​ foreach ($headerTitleArr as $i => $v) {

​ ​ ​

​ ​ ​ $headerTitleArr[$i] = iconv (‘utf-8’, ‘gbk’, $v);

​ ​ ​

​ ​ ​ }

​ ​ ​

​ ​ ​ #每次查询的条数

​ ​ ​

​ ​ ​ $pageSize = 5000;

​ ​ ​

​ ​ ​ #分批导的次数

​ ​ ​

​ ​ ​ $pages = ceil($totalNums / $pageSize);

​ ​ ​

​ ​ ​ #打开文件流

​ ​ ​

​ ​ ​ $ fp = fopen($pathName, ‘a’);

​ ​ ​

​ ​ ​ #将数据格式化为CSV格式并写入到文件流中

​ ​ ​

​ ​ ​ fputcsv($fp, $headerTitleArr);

​ ​ ​

​ ​ ​ #主体内容

​ ​ ​

​ ​ ​ $paegNum = 0;

​ ​ ​

​ ​ ​ for ($i=0; $i <$pages ; $i++) {

​ ​ ​

​ ​ ​ $data = Db::table(‘t_excle’)->limit($paegNum,$pageSize)->field(‘*’)->select();

​ ​ ​

​ ​ ​ foreach ($data as $fields) {

​ ​ ​

​ ​ ​ foreach ($fields as $key => &$v) {

​ ​ ​

​ ​ ​ // CSV的Excel支持GBK编码,一定要转换,否则乱码

​ ​ ​

​ ​ ​ // 加”\t”防止数字导出时变成科学计数

​ ​ ​

​ ​ ​ $v = iconv(‘utf-8’, ‘gbk’, $v.”\t”);

​ ​ ​

​ ​ ​ }

​ ​ ​

​ ​ ​ fputcsv($fp, $fields);

​ ​ ​

​ ​ ​ //这边可记录下数据的最后一次的位置,便于查看排错定位。

​ ​ ​

​ ​ ​ }

​ ​ ​

​ ​ ​ unset($data);//释放变量的内存

​ ​ ​

​ ​ ​ $paegNum += $pageSize;

​ ​ ​

​ ​ ​ }

​ ​ ​

​ ​ ​ fclose ($fp);

​ ​ ​

​ ​ ​ #输出下载链接,url为下载的域名

​ ​ ​

​ ​ ​ return $url.$pathName;

​ ​ ​

​ ​ ​ }

对于一个请求来说PHP是单线程的,大数据量的导出又是最耗时的,搞不好其他请求就阻塞了。

小数据量的话,可以直接浏览器输出;

大数据量的话,可以生成excle下载链接;推荐使用swoole异步框架处理请求。

1.当客服在后台系统点击下载后,可先返回个提示或是生成一条下载记录;

2.在后台异步处理excle导出操作;

3.客服主动刷新页面查看是否有下载链接生成。

再上代码(生成excle直接浏览器输出):

​ ​ public function downOrderData($timeStart, $timeEnd)

​ ​

​ ​{

​ ​

​ ​ set_time_limit(0);

​ ​

​ ​ $columns = [

​ ​

​ ​ ‘序号ID’, ‘姓名’, ‘电话’, ……

​ ​

​ ​ ];

​ ​

​ ​ $csvFileName = ‘订单数据’ . $timeStart .’_’. $timeEnd . ‘.xlsx’;

​ ​

​ ​ //设置好告诉浏览器要下载excel文件的 header s

​ ​

​ ​ 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 = ‘100000’//从数据库获取总量,假设是十万

​ ​

​ ​ $perSize = 1000;//每次查询的条数

​ ​

​ ​ $pages = ceil($accessNum / $perSize);

​ ​

​ ​ $lastId = 0;

​ ​

​ ​ for($i = 1; $i <= $pages; $i++) {

​ ​

​ ​ $data = Db::table(‘t_excle’)->limit($lastId ,$pageSize)->field(‘*’)->select();

​ ​

​ ​ foreach($data as $value) {

​ ​

​ ​ mb_convert_variables(‘GBK’, ‘UTF-8’, $value);

​ ​

​ ​ fputcsv($fp, $value);

​ ​

​ ​ $lastId = $value[‘id’];

​ ​

​ ​ }

​ ​

​ ​ unset($data);//释放变量的内存

​ ​

​ ​ //刷新输出缓冲到浏览器

​ ​

​ ​ ob_flush();

​ ​

​ ​ flush();//必须同时使用 ob_flush() 和flush() 函数来刷新输出缓冲。

​ ​

​ ​ }

​ ​

​ ​ fclose($fp);

​ ​

​ ​ exit();

​ ​

​ ​}

PS:更多信息交流,请关照:倒影Amoy

活着就是为了改变世界,难道还有其他原因吗?—-乔布斯

请输入图片描述

文章来源:智云一二三科技

文章标题:PHPexcle大数据量导出

文章地址:https://www.zhihuclub.com/154038.shtml

关于作者: 智云科技

热门文章

网站地图