如何在php中解析包含1500万行数据的csv文件

5 php csv fgetcsv

我有一个脚本可以解析 CSV 文件并开始验证电子邮件。这对于 1000 行来说效果很好。但在 1500 万行时,它显示内存耗尽错误。文件大小为 400MB。有什么建议么?如何解析和验证它们?

服务器规格:Core i7 和 32GB RAM

function parse_csv($file_name, $delimeter=',') {
  $header = false;
  $row_count = 0;
  $data = [];

  //  clear any previous results
  reset_parse_csv();

  // parse
  $file = fopen($file_name, 'r');
  while (!feof($file)) {
    $row = fgetcsv($file, 0, $delimeter);
    if ($row == [NULL] || $row === FALSE) { continue; }
    if (!$header) {
      $header = $row;
    } else {
      $data[] = array_combine($header, $row);
      $row_count++;
    }
  }
  fclose($file);

  return ['data' => $data, 'row_count' => $row_count];

}

function reset_parse_csv() {
  $header = false;
  $row_count = 0;
  $data = [];    
}
Run Code Online (Sandbox Code Playgroud)

fel*_*ins 13

将大型数据集(文件行等)推入数组会增加内存使用量,这与处理的项目数量成正比。因此,在这种情况下,文件越大,内存使用量就越大。

因此,与其将数据收集到数组中,不如就地处理它:

$file = fopen($file_name, 'r');
while (!feof($file)) {
    $row = fgetcsv($file, 0, $delimeter);
    if ($row == [NULL] || $row === FALSE) { continue; }
    if (!$header) {
        $header = $row;
    } else {
        // do whatever's intended to do with row
        // instead of $data[] = array_combine($header, $row);
        do_something($row);
    }
}
Run Code Online (Sandbox Code Playgroud)

这里的主要区别是:
您不会立即(从内存中)获取并使用所有数据您可以按需获取项目(如流)并对其进行处理,一次处理一个项目。它对内存使用有巨大影响。

但是,如果实际工作负载无法轻松移动到循环内部(例如,它是一个需要处理数组的函数),您可以将处理移动到其他地方,同时保持较低的内存占用量。为此,您可以使用生成器

阅读 PHP 文档,它非常适合您的情况(强调我的情况):

生成器允许您编写使用 foreach 迭代一组数据的代码,而无需在内存中构建数组,这可能会导致您超出内存限制,或者需要大量的处理时间来生成。

像这样的东西:

$file = fopen($file_name, 'r');
while (!feof($file)) {
    $row = fgetcsv($file, 0, $delimeter);
    if ($row == [NULL] || $row === FALSE) { continue; }
    if (!$header) {
        $header = $row;
    } else {
        // do whatever's intended to do with row
        // instead of $data[] = array_combine($header, $row);
        do_something($row);
    }
}
Run Code Online (Sandbox Code Playgroud)

进而:

$generator = csv_read('rdu-weather-history.csv', ';');

do_stuff_with_array($generator);
Run Code Online (Sandbox Code Playgroud)

这里,$generator变量并不同时保存所有数据。一方面,它的行为很像数组,并且可以在foreach()语句内部使用。另一方面,它的行为就像一个流,一次读取一个项目


PS:上面的 CSV 文件取自: https: //data.townofcary.org/api/v2/catalog/datasets/rdu-weather-history/exports/csv