PHP加载大型CSV文件-内存问题

4
我有以下代码。
$file="postcodes.csv";
$csv= file_get_contents($file);
$array = array_map("str_getcsv", explode("\n", $csv));
$json = json_encode($array);
print_r($json);

postcodes.csv的大小为603MB,是一个较大的文件。

在php.ini中,如果我有

memory_limit=1024M

我会得到以下错误

Fatal error: Allowed memory size of 1073741824 bytes exhausted (tried to allocate 256 bytes) in ...

如果我将内存限制增加到2056,我会得到以下错误

Fatal error: Out of memory (allocated 1919680512) (tried to allocate 36 bytes) in...

将它更改为-1也会有类似的问题。

那么如何在不遇到内存问题的情况下加载这个csv文件呢?

谢谢


3
除非你确实需要一次性将所有行存入内存(这种情况很少见),我建议分批进行处理,最糟糕的情况是“读取一行,处理它,输出,重复”。 - Piskvor left the building
2
我同意上面的观点,但为了分析这个问题:PHP是否将每个字符转换为本地CPU字长进行读取?如果是这样,请尝试将您的memory_limit增加到输入文件中字符数的4倍或8倍(根据您的架构),看看是否有帮助。免责声明:我还没有在PHP中进行过文件读取。 - underscore_d
2
第2至4行基本上意味着:将所有约600 MB的数据至少同时保存三次(作为字符串、数组和JSON字符串)在内存中。这实际上是一个如何不应该做这样的事情的很好的例子。抱歉 :) - mermshaus
4个回答

2
答案很简单,您需要在php.ini中增加memory_limit的值,因为文件大小为603MB,但是在代码中使用所有这些函数会从json数据中创建一些内存结构,这超过了603MB。或者您可以通过改变代码来优化内存使用,但是您的问题是如何增加内存限制。

2

您可以逐行读取您的文件。

例如:

$file="postcodes.csv";
$array = array();
if (($handle = fopen($file, "r")) !== FALSE) {
    while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
        $array[]=$data;
    }
    fclose($handle);
}
$json = json_encode($array);
print_r($json);

但是,如果你有大量的数据且数组太大,仍然可能出现内存问题。


2

与其将整个文件读入变量,解析换行符,然后对每个数组元素执行str_getcsv,不如考虑根据需求,获取包含每行所有值的完整json或多个json字符串,每个字符串对应一个csv行。

$h = fopen("postcodes.csv",);

if ($h !== FALSE) {
    $str ='';
    while (($data = fgetcsv($handle)) !== FALSE) {

        $str .= json_encode($data); // add each json string to a string variable, save later
        // or
        $array[]=$data;     
    }
}
fclose($h);

$finalJsonString = json_encode($array);

我不建议你打印整个这样大小的arrayjson对象,因为这会很难跟踪。


1
如果你在读取大文件,我建议使用文件指针和fgetcsv()函数逐行循环而不是加载整个文件。此外,换行符并不一定意味着CSV行的结尾,explode("\n", $csv)可能会给你一些不需要的结果... 使用fgetcsv()会更安全。

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