最新消息:yaf表单扩展中新增加了浮点数、日期和集合的校验。php yaf框架扩展实践三——表单

phpexcel读取大文件时内存超过上限的问题

PHP 2977浏览 0评论

先放上测试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读取大文件时内存超过上限的问题

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址