Php 在没有超时和内存错误的情况下处理非常大的csv文件

Php 在没有超时和内存错误的情况下处理非常大的csv文件,php,csv,import,timeout,Php,Csv,Import,Timeout,目前,我正在为一个非常大的CSV文件编写一个导入脚本。问题是,大多数情况下,由于超时或抛出内存错误,它会在一段时间后停止 我现在的想法是以“100行”的步骤解析CSV文件,在100行之后自动调用脚本。我试图用header(location…)来实现这一点,并用get传递当前行,但没有按照我想要的那样工作 有更好的方法吗?或者有人知道如何消除内存错误和超时吗?如果不关心需要多长时间和需要多少内存,只需增加此脚本的值即可。只需在脚本顶部添加以下行: ini_set('memory_limit', '

目前,我正在为一个非常大的CSV文件编写一个导入脚本。问题是,大多数情况下,由于超时或抛出内存错误,它会在一段时间后停止

我现在的想法是以“100行”的步骤解析CSV文件,在100行之后自动调用脚本。我试图用header(location…)来实现这一点,并用get传递当前行,但没有按照我想要的那样工作


有更好的方法吗?或者有人知道如何消除内存错误和超时吗?

如果不关心需要多长时间和需要多少内存,只需增加此脚本的值即可。只需在脚本顶部添加以下行:

ini_set('memory_limit', '512M');
ini_set('max_execution_time', '180');
通过该函数,您可以了解脚本需要多少内存才能为内存限制找到合适的值


您可能还想看看哪一个允许您逐行读取文件。我不确定这是否需要更少的内存,但我真的认为这会起作用。但即使在这种情况下,您也必须将最大执行时间增加到一个更高的值。

哦。只需将此脚本称为CLI,而不是通过愚蠢的web界面。因此,没有执行时间限制会影响它。
不要永远保存解析结果,而是立即将它们写下来——这样,您也不会受到内存限制的影响

我曾经以流式方式读取120MB的csv(这是正确的英语吗?)。逐行读取,然后将每一行插入数据库。这样,在每次迭代中,内存中只保留一行。脚本仍然需要20分钟才能运行。也许下次我会尝试Python…不要尝试将一个巨大的csv文件加载到数组中,那样会消耗大量内存

// WDI_GDF_Data.csv (120.4MB) are the World Bank collection of development indicators:
// http://data.worldbank.org/data-catalog/world-development-indicators
if(($handle = fopen('WDI_GDF_Data.csv', 'r')) !== false)
{
    // get the first row, which contains the column-titles (if necessary)
    $header = fgetcsv($handle);

    // loop through the file line-by-line
    while(($data = fgetcsv($handle)) !== false)
    {
        // resort/rewrite data and insert into DB here
        // try to use conditions sparingly here, as those will cause slow-performance

        // I don't know if this is really necessary, but it couldn't harm;
        // see also: http://php.net/manual/en/features.gc.php
        unset($data);
    }
    fclose($handle);
}

我发现上传文件并使用mysql的LOAD DATA LOCAL query插入是一个快速的解决方案,例如:

    $sql = "LOAD DATA LOCAL INFILE '/path/to/file.csv' 
        REPLACE INTO TABLE table_name FIELDS TERMINATED BY ',' 
        ENCLOSED BY '\"' LINES TERMINATED BY '\r\n' IGNORE 1 LINES";
    $result = $mysqli->query($sql);

在内存消耗方面,fgetcsv()和fgets()之间似乎存在巨大的差异。 一个只有一列的简单CSV通过了我的512M内存限制,使用fgetcsv()只保存50000条记录,并花了8分钟报告

使用fgets()只需3分钟就可以成功处理649175条记录,而我的本地服务器甚至都不需要额外的空气

因此,如果csv中的列数有限,我的建议是使用fgets()。在我的例子中,fgets()直接返回第1列中的字符串。 对于多个列,可以在一次性数组中使用explode(),在每次记录操作后将其取消设置()。
竖起大拇指回答3@ndkauboy

您的CSV文件有多大?你需要将其导入数据库吗?请查看我的答案,其中还包括一些比较。当然,如果你知道文件的大小始终相同,这是一个很好的方法。如果你知道它不大于特定大小,它也可以工作。哇,我从5分钟以上导入了64000条csv记录,时间不到5秒。这太棒了!