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