PHPExcel使用过滤器按块读取excel
PHPExcel读取EXCEL非常消耗内存(尤其是上万条数据,很容易出现内存不足),可以使用分批、异步读取,思路:
1、获取表中记录总行数
2、每次读取N条写入数据库,并返回最后一条的行号
3、根据上次返回的行号使用AJAX等方式循环第2步
相应代码可从下方示例中分离
//加载PHPExcel类库 require_once FCPATH.'app/manage/libraries/PHPExcel/IOFactory.php'; //按块读取EXCEL,减少内存占用 class chunkReadFilter implements PHPExcel_Reader_IReadFilter{ private $_startRow = 0; private $_endRow = 0; //设置要读取的块开始行、结束行 public function setRows($startRow, $chunkSize) { $this->_startRow = $startRow; $this->_endRow = $startRow + $chunkSize; } //确定当前行是否读取 public function readCell($column, $row, $worksheetName = '') { //读取首行(标题行)和块区间内的行数据 //return (($row == 1) || ($row >= $this->_startRow && $row < $this->_endRow)) ? TRUE : FALSE; //只读取块区间内的行数据 return ($row >= $this->_startRow && $row < $this->_endRow) ? TRUE : FALSE; } } //执行导入 function import_do($arr_fields){ $excelfields = P('fields'); //要导入的字段和顺序 $excelfile = P('excelfile'); //要导入的excel文件 $skiplines = P('skiplines'); //跳过行数 $deletefile = P('deletefile'); //导入成功后删除excel文件 if(!$excelfields){ return $this->_display('请添加要导入的字段'); }else{ $excelfields = explode('|', $excelfields); } if(! $excelfile)return $this->_display('请上传要导入的文件'); is_lng($skiplines) OR $skiplines=0; $deletefile = $deletefile=='1' ? TRUE : FALSE; $time=$this->input->server('REQUEST_TIME'); //设置超时时间为99秒 set_time_limit(99); $excelfile = FCPATH.substr($excelfile, 1); $inputFileType = PHPExcel_IOFactory::identify($excelfile); $objReader = PHPExcel_IOFactory::createReader($inputFileType); $objReader->setReadDataOnly(true); $chunkSize = 500; //每次读取记录数 $chunkFilter = new chunkReadFilter(); //实例化按块读取过滤器 $objReader->setReadFilter($chunkFilter); //使用过滤器 $chunkFilter->setRows(1,1); //从第一条开始读取1条,据此获取activeShieetIndex $objPHPExcel = $objReader->load($excelfile); $activeSheetIndex = $objPHPExcel->getActiveSheetIndex(); $worksheetData = $objReader->listWorksheetInfo($excelfile); // 列出工作表列表 $activeSheetInfo = $worksheetData[$activeSheetIndex]; /* * $activeSheetInfo Array( [worksheetName] => 信息 [lastColumnLetter] => AQ [lastColumnIndex] => 42 [totalRows] => 21 [totalColumns] => 43 ) */ for ($startRow = $skiplines+1+5000; $startRow <= $activeSheetInfo['totalRows']; $startRow += $chunkSize) { echo 'Loading WorkSheet using configurable filter for headings row 1 and for rows ',$startRow,' to ',($startRow+$chunkSize-1),'<br />'; //设置本次循环要读取的记录 $chunkFilter->setRows($startRow,$chunkSize); //根据过滤器读取数据 $objPHPExcel = $objReader->load($excelfile); $sheetData = $objPHPExcel->getActiveSheet()->toArray(null,true,true,true); $sheetData = array_slice($sheetData, $startRow-1); //echo '<pre>'; //print_r($sheetData); } echo memory_get_peak_usage(), ', ', memory_get_usage(), ', ', (microtime(true)-$time); exit; }