我想知道是否有人可以解决这个问题.PHP 5.3.0:)
我有一个循环,它抓取CSV文件的内容(大,200mb),处理数据,为mysql插入构建一堆变量,一旦循环完成并创建变量,我插入信息。
现在首先,mysql插件运行完美,没有延迟,一切都很好,但是它是LOOP本身有延迟,我最初使用fgetcsv()读取CSV文件,但与file_get_contents()相比,这有严重延迟 - 所以我切换到file_get_contents()。循环将在几秒钟内执行,直到我尝试添加一个函数(我还在循环内添加了表达式而没有函数来查看它是否有帮助)来创建一个包含每行的CSV数据的数组,这个是什么导致解析时间严重延迟! (基于这个200mb文件的差异大约是30秒,但我想根据csv文件的文件大小)
这是一些代码,所以你可以看到我在做什么:
$filename = "file.csv";
$content = file_get_contents($filename);
$rows = explode("\n", $content);
foreach ($rows as $data) {
$data = preg_replace("/^\"(.*)\"$/","$1",preg_split("/,(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/", trim($data))); //THIS IS THE CULPRIT CAUSING SLOW LOADING?!?
}
运行上面的循环,几乎不会立即执行:
$data = preg_replace("/^\"(.*)\"$/","$1",preg_split("/,(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/", trim($data)));
我也尝试过如下创建一个函数(在循环之外):
function csv_string_to_array($str) {
$expr="/,(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/";
$results=preg_split($expr,trim($str));
return preg_replace("/^\"(.*)\"$/","$1",$results);
}
并调用函数而不是一个衬垫:
$data = csv_string_to_array($data);
再次没有运气:(
任何帮助都会受到赞赏,我猜测fgetcsv函数基于它引起的延迟以非常类似的方式执行,循环并从数据行创建数组。
丹尼
答案 0 :(得分:1)
正则表达式子表达式(以“(...)”为界)是问题所在。显示将这些添加到表达式可以大大降低其性能,这是微不足道的。我要尝试的第一件事是停止使用preg_replace()来简单地删除前导和尾随双引号(trim()将是更好的选择)并看看它有多大帮助。之后,您可能需要尝试使用非正则表达式来解析该行。
答案 1 :(得分:0)
我部分找到了一个解决方案,我发送批处理一次只循环1000行(php循环1000,直到到达文件末尾)。
我只是设置:
$data = preg_replace("/^\"(.*)\"$/","$1",preg_split("/,(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/", trim($data)));
1000行上的,因此没有为导致问题的WHOLE文件设置它。
现在循环并在1-2秒内将1000行插入mysql数据库,我很满意。我已经设置脚本循环1000行,记住它的最后位置,然后循环到下一个1000直到它到达结束,它似乎工作正常!
答案 2 :(得分:0)
我说主要的罪魁祸首是preg_split()regexp的复杂性。 爆炸()可能会吃几秒钟。
$content = file_get_contents($filename);
$rows = explode("\n", $content);
可以替换为:
$rows = file ($filename); // returns an array
但是,我从ITroubs获得上述建议,fgetcsv()可能是一个更好的解决方案。
答案 3 :(得分:0)
顺便说一句,我认为你的函数没有按照你的想法做到:当你退出循环时,它实际上不会修改$ rows数组。要做到这一点,你需要更多的东西:
foreach ($rows as $key => $data) {
$rows[$key]=preg_replace("/^\"(.*)\"$/","$1",preg_split("/,(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/", trim($data)));
答案 4 :(得分:0)
我建议使用fgetcsv来解析数据。看起来记忆可能是你最大的影响。因此,为了避免消耗200MB的RAM,您应该逐行解析,如下所示:
$fp = fopen($input, 'r');
while (($row = fgetcsv($fp, 0, ',', '"')) !== false) {
$out = '"' . implode($row, '", "') . '"'; // quoted, comma-delimited output
// perform work
}
或者:在preg中使用条件通常非常昂贵。使用explode()
和trim()
及其$charlist
参数处理这些行有时会更快。
另一种选择,如果您仍想使用preg,请添加S修饰符以尝试加速表达式。
http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php
<强>取值强>
当一个模式将被多次使用时,值得花更多时间分析它以加快匹配所需的时间。如果设置了此修改器,则执行此额外分析。目前,研究模式仅对没有单个固定起始字符的非锚定模式有用。