2011-09-06 102 views
19

目前我正在为一个非常大的CSV文件编写导入脚本。问题大多数时候会因为超时而停止,或者会引发内存错误。处理非常大的csv文件没有超时和内存错误

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

有没有更好的方法,或有人有一个想法如何摆脱内存错误和超时?

+2

你有多大的CSV文件?你需要将它导入数据库中? –

+0

查看我的答案http://stackoverflow.com/a/22744300/2037323其中还包括一些比较。 –

回答

44

我使用fgetcsv以流式方式读取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); 
} 
12

如果您不关心需要多长时间以及需要多少内存,则可以简单地增加此脚本的值。只需以下行添加到您的脚本的顶部:

ini_set('memory_limit', '512M'); 
ini_set('max_execution_time', '180'); 

随着memory_get_usage()你可以找到你的脚本需要多少内存找到memory_limit的一个很好的价值功能。

您可能还想看看fgets(),它允许您逐行读取文件。我不确定这是否会减少记忆,但我真的认为这会奏效。但即使在这种情况下,您也必须将max_execution_time增加到更高的值。

+1

如果您知道该文件的大小始终相同,那么这当然只是一种好方法。 –

+3

如果你知道它不大于speficic尺寸,它也可以。 – 2ndkauboy

-2

哦。只需将此脚本称为CLI,而不是通过愚蠢的Web界面。所以,没有执行时间限制会影响它。
并且不要永远保留解析结果,而是立即写下来 - 所以,你也不会受到内存限制的影响。

12

我发现上传文件,并使用MySQL的LOAD DATA LOCAL查询一个快速的解决方案如插入:

$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); 
+0

哇我从5分钟+导入一个64000记录csv少于5秒。这是太棒了! – Iznogood

相关问题