PHPexcle大数据量导出

1,157 阅读1分钟


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

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

过程中可能遇到的问题:

上代码(生成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文件的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 = '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();}


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

更多信息交流,敬请关注下面号