0

我有一个我无法控制的相当大的 csv 文件(至少对于网络而言)。它有大约 100k 行,并且只会变得更大。

我正在使用 Drupal 模块提要根据这些数据创建节点,它们的解析器以 50 行为一组进行解析。但是,他们的解析器不能正确处理引号,并且无法解析大约 60% 的 csv 文件。fgetcsv 有效,但据我所知并没有批量处理。

在尝试使用 fgetcsv 读取整个文件时,PHP 最终耗尽了内存。因此,我希望能够将事情分解成更小的块。这可能吗?

4

3 回答 3

2

fgetcsv()通过从给定的文件指针一次读取一行来工作。如果 PHP 内存不足,也许您正试图一次解析整个文件,将其全部放入一个巨大的数组中。解决方案是逐行处理它而不将其存储在一个大数组中。

要更直接地回答批处理问题,请从文件中读取n行,然后使用ftell()查找文件中结束的位置。记下这一点,然后您可以在将来的某个时间通过调用fseek()before回到它fgetcsv()

于 2011-01-03T17:32:01.823 回答
2

好吧,创建一个函数来解析一堆行:

function parseLines(array $lines) {
    foreach ($lines as $line) {
        //insert line into new node
    }
}

然后,只需批量处理:

$numberOfLinesToBatch = 50;
$f = fopen($file, 'r');
if (!$f) die('implement better error checking');

$buffer = array();
while ($row = fgetcsv($f)) {
    $buffer[] = $row;
    if (count($buffer) >= $numberOfLinesToBatch) {
        parseLines($buffer);
        $buffer = array();
    }
}
if (!empty($buffer)) {
    parseLines(buffer);
}

fclose($f);

它将数据流式传输,您可以通过调整变量来调整它缓冲的行数......

于 2011-01-03T17:36:59.453 回答
0

我怀疑问题在于您在内存中存储了太多信息,而不是您如何从磁盘读取 CSV 文件。(即: fgetcsv 一次只会读取一行,所以如果一行的数据导致你内存不足,你就有麻烦了。)

因此,您只需使用以下方法:

  1. 将“x”行读入数组。
  2. 处理这些信息
  3. 清除任何临时变量/数组。
  4. 重复直到 FEOF。

或者,您可以通过 PHP 的命令行版本执行 CSV 处理,并使用具有更大内存限制的自定义 php.ini。

于 2011-01-03T17:27:27.970 回答