先放上测试demo下载:点击下载
用phpexcel读取excel文件的时候,如果文件小一切都正常,速度还挺快,要是文件大了就可能会碰到处理超时和内存过大的问题。可能会碰到如下类似的错误:
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 32 bytes)
碰到这种情况,有一种处理方式是修改php.ini配置memory_limit,调高允许的最大内存。不过这种情况不是特别推荐,最好是能够优化程序,使得程序占用的内存变小,朝着这个思路查了下代码,发现phpexcel在load文件的时候就会把excel文件中的数据都读取进来,要是数据量多,占用的内存能不大吗!
$phpexcel = $excelReader->load($excelFile); var_dump($phpexcel);
试着打印这个变量,可以发现这个变量内存储了excel每行的数据。
于是我考虑每一次只读取若干条,而不是读取全部,这样应当就能减少内存的占用,幸好phpexcel提供了这样的方式。
需要先建一个类,实现PHPExcel_Reader_IReadFilter接口中的readCell方法,在readCell方法中就可以进行过滤了。
/** * 读取excel过滤器 */ class PHPExcelReadFilter implements PHPExcel_Reader_IReadFilter { public $startRow = 1; public $endRow; public function readCell($column, $row, $worksheetName = '') { //如果endRow没有设置表示读取全部 if (!$this->endRow) { return true; } //只读取指定的行 if ($row >= $this->startRow && $row <= $this->endRow) { return true; } return false; } }
如何调用呢?在初始化excel读取对象后,调用对象的setReadFilter方法就可以了。参考如下方法
/** * 读取excel转换成数组 * * @param string $excelFile 文件路径 * @param string $excelType excel后缀格式 * @param int $startRow 开始读取的行数 * @param int $endRow 结束读取的行数 * @retunr array */ function readFromExcel($excelFile, $excelType = null, $startRow = 1, $endRow = null) { include_once __DIR__ . '/PHPExcel.php'; $excelReader = \PHPExcel_IOFactory::createReader("Excel2007"); $excelReader->setReadDataOnly(true); //如果有指定行数,则设置过滤器 if ($startRow && $endRow) { $perf = new PHPExcelReadFilter(); $perf->startRow = $startRow; $perf->endRow = $endRow; $excelReader->setReadFilter($perf); } $phpexcel = $excelReader->load($excelFile); $activeSheet = $phpexcel->getActiveSheet(); if (!$endRow) { $endRow = $activeSheet->getHighestRow(); //总行数 } $highestColumn = $activeSheet->getHighestColumn(); //最后列数所对应的字母,例如第2行就是B $highestColumnIndex = \PHPExcel_Cell::columnIndexFromString($highestColumn); //总列数 $data = array(); for ($row = $startRow; $row <= $endRow; $row++) { for ($col = 0; $col < $highestColumnIndex; $col++) { $data[$row][] = (string) $activeSheet->getCellByColumnAndRow($col, $row)->getValue(); } } return $data; }
这样就能减少内存的占用了。只是这样不是一次性读取excel的内容,在程序外围需要做一个循环读取的功能,这个比较简单,就不给代码了。
测试demo下载
转载请注明:快乐编程 » phpexcel读取大文件时内存超过上限的问题
{
// Root-relative paths
if (strpos($fileName, '//') !== false) {
$fileName = substr($fileName, strpos($fileName, '//') + 1);
}
$fileName = PHPExcel_Shared_File::realpath($fileName);
// Sadly, some 3rd party xlsx generators don't use consistent case for filenaming
// so we need to load case-insensitively from the zip file
//!!!!!!!!!!!!!!!!!!!!在这里挂了,这里也是要读整个文件!!!!!!!!!!!!!!!!!!!!!!!!!!
// Apache POI fixes
$contents = $archive->getFromIndex(
$archive->locateName($fileName, ZIPARCHIVE::FL_NOCASE)
);
if ($contents === false) {
$contents = $archive->getFromIndex(
$archive->locateName(substr($fileName, 1), ZIPARCHIVE::FL_NOCASE)
);
}
return $contents;
}