更快地逐行读取文件?

时间:2017-05-31 09:49:37

标签: php mysql fgets

在PHP中,我使用fopen( )fgets( )fclose( )逐行读取文件。它运作良好。但我有一个脚本(从CLI运行),必须处理三百个5GB的文本文件。那是大约30亿fgets( )。所以它工作得很好,但在这种规模下,微小的速度节省将非常快。所以我想知道是否有任何技巧来加快这个过程?

我唯一想到的就是让fgets( )一次读取多行。它看起来并不支持它,但理论上我可以说连续20个$line[] = fgets($file);,然后处理数组。这与在一个命令中读取多行并不完全相同,因此它可能没有任何影响。但是我知道排队你的mysql插件并将它们作为一个巨大的插件发送(我将在更多测试和基准测试之后在这个脚本中实现的另一个技巧)将节省大量时间。

更新4/13/19 这是我选择的解决方案。最初我有一个更复杂的方法来切断每次读取的结束,但后来我意识到你可以做得更简单。

$index_file = fopen( path to file,"r" );
$chunk = "";
while ( !feof($index_file) )
    {
    $chunk .= fread($index_file,$read_length);
    $payload_lines = explode("\n",$chunk);

    if ( !feof($index_file) )
        { $chunk = array_pop($payload_lines); }

    }

当然,PHP具有一切功能。因此,我将每次读取分解为一个行数组,并将array_pop()数组中的最后一项返回到“读取缓冲区”的开头。最后一部分可能是分裂的,但不一定是分裂的。但无论哪种方式,它都会重新进入并通过下一个循环进行处理(除非我们对文件进行了处理,否则我们不会弹出它)。

你唯一需要注意的是,如果你有一条线太久以至于一次读取不会捕获整个事物。但要知道你的数据,这可能不会有麻烦。对我来说,我正在解析一个json-ish文件,而且我一次只能读取128 KB,所以我的阅读总会有很多换行符。

注意:我通过做一百万个基准测试来确定128 KB,并找到我的服务器处理绝对最快的大小。这个解析函数将运行300次,因此每保存一次,节省了5分钟的总运行时间。

1 个答案:

答案 0 :(得分:1)

可能更快的一种可能方法是使用selectCountry(e) { let country = e.currentTarget.dataset.country; // country will be "KH" for example } 读取文件的大块,用换行符拆分然后处理这些行。您必须考虑到块可能会切断线路,您必须检测到这些并将它们粘合在一起。

一般来说,一次性读取的块越大,过程应该越快。在可用内存的限制范围内。

来自fread() docs

  

请注意,fread()从文件指针的当前位置读取。使用ftell()查找指针的当前位置,使用rewind()来回退指针位置。