0

我有一个大约 200,000 行的日志文件。每行的格式为:

AAA||BBB|C|DDD||

现在我使用以下解析循环解析值:

$fh = fopen($filename, 'r');
if($fh === FALSE) {
  return null;
}
$result = array();
while(!feof($fh)) {
  $line = fgets($fh);
  $tokens = explode('||', $line);
  $a = $tokens[0];
  list($b, $c, $d) = explode('|', $tokens[1]);
  // then I can get the values of AAA , BBB , C and DDD and put it into an array
  $result[$a] = array('a' => $a, 'b' => $b, 'c' => $c, 'd' => $d);
}

$result[$a]包含我需要的所有内容,但解析时间约为 2.1 秒。我能做些什么来降低解析速度?

4

3 回答 3

4

感谢所有的答案和评论。我对以下功能进行了基准测试:

使用以下代码(省略了while循环):

// fgets ( same code in the question )
$tokens = explode('||', $line);
$a = $tokens[0];
list($b, $c, $d) = explode('|', $tokens[1]);
$result[$a] = array('a' => $a, 'b' => $b, 'c' => $c, 'd' => $d);

// fgetcsv
ini_set('auto_detect_line_endings',TRUE);
list($a, $nouse1, $b, $c, $d, $nouse2, $nouse3) = fgetcsv($fh, 200, '|');
$result[$a] = array('a' => $a, 'b' => $b, 'c' => $c, 'd' => $d);

// stream_get_line
$line = stream_get_line($fh, 200, PHP_EOL);
$tokens = explode('||', $line);
if(count($tokens) != 3) {
  continue;
}
$a = $tokens[0];
list($b, $c, $d) = explode('|', $tokens[1]);
$result[$a] = array('a' => $a, 'b' => $b, 'c' => $c, 'd' => $d);

// stream_get_line + str_getcsv
$line = stream_get_line($fh, 200, PHP_EOL);
list($a, $nouse1, $b, $c, $d, $nouse2, $nouse3) = str_getcsv($line, '|');
$result[$a] = array('a' => $a, 'b' => $b, 'c' => $c, 'd' => $d);

// fgets + str_getcsv
$line = fgets($fh);
list($a, $nouse1, $b, $c, $d, $nouse2, $nouse3) = str_getcsv($line, '|');
$result[$a] = array('a' => $a, 'b' => $b, 'c' => $c, 'd' => $d);

他们在同一台测试机器中解析相同路径中的相同文本文件。行格式为:

AAA||BBB|C|DDD||

这是结果(测试了 3 次并取平均时间):

没想到,fgetcsv()是最慢的。但为什么 ?

旁注: stream_get_line()仅在 PHP 5 中可用。

于 2013-05-03T02:54:30.613 回答
1

PHP 中的文件解析很慢。不久前,我在 fgetcsv 和自定义 csv 函数之间进行了一些基准测试,而 fgetcsv 显然是赢家(我认为是 10 倍左右)。您应该能够重新排列代码以使用 fgetcsv,使用 '|' 作为你的分隔符。

于 2013-05-02T06:21:25.913 回答
0

嗯,我不确定这会有多大帮助,但是在 | 上爆炸呢?并分配 $a = $tokens[0]、$b = $tokens[2] 等。您将每次迭代的爆炸调用减少一个。

您也可以通过使用带有 '|' 的 fgetcsv 来实现类似的效果 作为你的分隔符。同样,不确定这会真正改善多少。

于 2013-05-02T06:19:12.447 回答