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

标签 php arrays csv foreach

我在尝试在 foreach 循环中使用 array_combine 时遇到了麻烦。最终会出现错误:

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

这是我的代码:

$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;

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

$csvData = $this->getData($file)

我使用 while 循环来读取 CSV 并将其分配到一个数组中,它工作正常,没有任何问题。问题来自于 array_combine 和 foreach 循环。

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

已更新

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

$data = array();
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)) {
    $data[] = $rowData;
}
fclose($fh);
return $data;

更新2

如果您正在使用 <=20,000~30,000 行的 CSV 文件,上面的代码可以正常工作。从 50,000 行及以上,内存将耗尽。

最佳答案

实际上,您在内存中保留(或试图保留)整个数据集的两个不同副本。首先,使用 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;

关于在 foreach 循环中使用 array_combine 时 PHP 内存耗尽,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37341575/

相关文章:

带有 foreach 和 fetch 的 PHP PDO

python - "#using-proxy-artist".format(orig_handle) 带饼图(来自 CSV 的数据) Matplotlib

javascript - 导入不带转义引号的 csv javascript

r - append 具有不同列数量和拼写的 csv

php - 没有 php artisan 护照的护照 : install on deploying server

php - Magento : Getting Product Collection Sorted by minimum price

arrays - 平面嵌套对象的闭包?

Java:如何按降序排列数组?

c++ - 如何从派生类实例化基类中的数组?

php - Yii2 - 获取其他用户的访问权限