在foreach循环中使用array_combine时,PHP内存耗尽

时间:2016-05-20 08:22:02

标签: php arrays csv foreach

尝试在[NSBundle bundleWithIdentifier:@"org.cocoapods.xyz"]循环中使用array_combine时遇到了麻烦。它最终会出错:

foreach

这是我的代码:

PHP Fatal error:  Allowed memory size of 268435456 bytes exhausted (tried to allocate 85 bytes) in

我使用的源文件CSV大约有1,000,000行。这一行

$data = array();
$csvData = $this->getData($file);
if ($columnNames) {
    $columns = array_shift($csvData);
    foreach ($csvData as $keyIndex => $rowData) {
        $data[$keyIndex] = array_combine($columns, array_values($rowData));
    }
}

return $data;

我使用while循环读取CSV并将其分配到一个数组中,它没有任何问题。麻烦来自$csvData = $this->getData($file) array_combine循环。

您有什么想法解决这个问题,或者只是想找到更好的解决方案吗?

已更新

以下是读取CSV文件的代码(使用while循环)

foreach

更新2

如果你正在使用CSV文件< = 20,000~30,000行,上面的代码没有任何问题。从50,000行以上,内存将耗尽。

1 个答案:

答案 0 :(得分:4)

事实上,您在整个数据集中保留(或试图保留)两个不同的副本。首先,使用getData()将整个CSV日期加载到内存中,然后通过循环内存中的数据并创建新数组,将数据复制到$data数组中。

在加载CSV数据时,您应该使用基于流的读取,以便只在内存中保留一个数据集。如果您使用的是PHP 5.5+(顺便说一句,您应该这样做),这很简单,只需将getData方法更改为:

protected function getData($file) {
    if (!file_exists($file)) {
        throw new Exception('File "' . $file . '" do not exists');
    }

    $fh = fopen($file, 'r');
    while ($rowData = fgetcsv($fh, $this->_lineLength, $this->_delimiter, $this->_enclosure)) {
        yield $rowData;
    }
    fclose($fh);
}

这使用了一个所谓的generator,这是一个PHP> = 5.5的功能。其余的代码应该继续工作,因为getData的内部工作方式应该对调用代码透明(只有事实的一半)。

更新以解释如何解压缩列标题现在可以正常工作。

$data = array();
$csvData = $this->getData($file);
if ($columnNames) { // don't know what this one does exactly
    $columns = null;
    foreach ($csvData as $keyIndex => $rowData) {
        if ($keyIndex === 0) {
            $columns = $rowData;
        } else {
            $data[$keyIndex/* -1 if you need 0-index */] = array_combine(
                $columns, 
                array_values($rowData)
            );
        }
    }
}

return $data;