读取并解析非常大的文件内容

9
我将尝试解析一个大约1GB大小的制表符分隔文件。
当我运行脚本时,会出现以下情况:
Fatal error: Allowed memory size of 1895825408 bytes exhausted  (tried to allocate 1029206974 bytes) ...

目前我的脚本只有:

$file = file_get_contents('allCountries.txt') ;

$file = str_replace(array("\r\n", "\t"), array("[NEW*LINE]", "[tAbul*Ator]"), $file) ;

我已经在php.ini中将内存限制设置为-1,这样会得到以下结果:

Fatal error: Out of memory (allocated 1029963776) (tried to allocate 1029206974 bytes)

有没有办法部分打开文件,然后继续下一部分,以便一次使用的内存更少?


1
为什么不逐行处理文件呢?! - user554546
我很惊讶没有人提到生成器,请在这里检查我的答案:https://dev59.com/7HA75IYBdhLWcg3wqK__#54146788 - lloiacono
4个回答

14

是的,你可以逐行阅读:

$handle = @fopen("/tmp/inputfile.txt", "r");
if ($handle) {
    while (($buffer = fgets($handle, 4096)) !== false) {
        echo $buffer;
    }
    fclose($handle);
}

1
对于一个以制表符分隔的文件,请使用fgetcsv()以简化操作。 - Mark Baker

2

1

你确定是fopen出了问题而不是脚本超时设置?默认值通常为约30秒,如果读取文件的时间比这长,可能会导致超时。

另一个要考虑的因素可能是脚本的内存限制-将文件读入数组可能会触发此限制,因此请检查错误日志以查看内存警告。

如果以上两点都不是问题,您可以考虑使用fgets逐行读取文件并在读取时处理。

$handle = fopen("/tmp/uploadfile.txt", "r") or die("Couldn't get handle");
if ($handle) {
    while (!feof($handle)) {
        $buffer = fgets($handle, 4096);
        // Process buffer here..
    }
    fclose($handle);
}

编辑

PHP似乎不会抛出错误,它只会返回false。

$rawfile的路径是否相对于脚本运行的位置正确?也许尝试在此处为文件名设置绝对路径。


如果我只是将文件加载到内存中,大约需要2秒钟,错误发生在str_replace处,但我会尝试逐行建议。 - imperium2335
由于在这种情况下PHP尝试将相同大小的内存复制到另一个变量中,因此str_replace会出现错误。 - user1645055

1

是的,用fopen和fread/fgets来实现:

http://www.php.net/manual/en/function.fread.php

string fread ( resource $handle , int $length )

将$length设置为您想要读取的文件的数量。 使用$handle保存新读取的位置,然后使用fseek还可以稍后设置位置....


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接