0

我正在尝试读取大约 20mb 的大 excel 文件以导入 mysql。

我已经在互联网上搜索并找到了“块阅读”解决方案,但是它不起作用......或者对我来说太慢了,我不知道为什么。

这就是我正在做的事情:

// .....
// into MyReadFilter class.. this is the most important function:
public function readCell($column, $row, $worksheetName = '') {
        //  Only read the rows and columns that were configured
        if (($row == 1) || ($row >= $this->_startRow && $row < $this->_endRow)) {
            if (in_array($column,$this->_columns)) {
                return true;
            }
        }
        return false;
    }
// .....


$filter = new MyReadFilter(1, 22000); 
$chunkSize = 10;

$objReader = PHPExcel_IOFactory::createReader($inputFileType);
$objReader->setReadFilter($filter);
$objReader->setReadDataOnly(false); //not sure if this should be true


for ($startRow = 2; $startRow <= 65536; $startRow += $chunkSize) {

  echo "Reading";
  $filterSubset->setRows($startRow, $chunkSize);
  $objPHPExcel = $objReader->load($inputFileName); // this line takes like 40 seconds... for 10 rows?
  echo "chunk done! ";
}

但是,在 for 内部,$objReader->load() 大约需要 40 秒,事实上,在 2 次循环之后,我遇到了内存错误。

如果我在 for 中取消设置 $objReader,我可以让它在 for... 中运行大约 20 次(尽管需要大约 10 分钟)和.. 内存错误。

我想知道如果我使用过滤器,为什么加载函数似乎读取了所有文件,过滤器策略似乎解析所有行并为所有不需要的行返回 false ......不可能中止读取或真的只阅读所需的吗?

我已经尝试了几个 FilterClass 和代码片段,但得到了相同的结果......

4

1 回答 1

3

如果您正在使用过滤器,则阅读器仍在读取整个文件,但仅填充过滤器定义的 PHPExcel 对象单元格;并且 Reader 仍然需要在每次过滤过程中读取整个文件,这就是它变慢的原因。

由于原始电子表格文件的结构,Reader 需要读取整个文件。单元格数据不以单元格格式存储,单元格内容也可以单独存储。读者需要将所有这些放在一起。您不能在满足过滤条件时简单地中止阅读器,因为阅读器无法知道它已经完成......如果您有一个过滤器将负载限制在单元格 A1:C3,那么您可以'在读取 B3 后不中止,因为您不知道文件中的单元格 B2 是否在该单元格之后,或者文件中可能有与单元格 A1 相关联的注释。在整个文件被加载和解析之前,你不能开始过滤。

PHPExcel 中的主要内存使用是 PHPExcel 对象,特别是单元格(在 32 位 PHP 上通常约为 1k/单元格)......这里提供的减少内存的主要解决方案是单元格缓存。这可以(使用 SQLite 缓存)将单元内存使用量减少到 0k/单元,但以速度为代价。

Reader 使用的内存并不比 Excel 文件(解压缩)本身的大小多多少,因此通常内存问题要小得多;但这正在通过从 SimpleXML 切换到 XMLReader 来解决(对于基于 XML 的电子表格格式)。但这取决于正在加载的文件的格式;xls 格式文件与 xlsx 文件非常不同(xlsx 会从中受益,xls 不会)并且还取决于开发人员能够找到时间来执行此操作 - 但它在来年的路线图上,并且可以工作已经开始了。

于 2013-04-07T09:38:23.427 回答