大家早上好!当我试图处理高达4GB的巨大csv文件时,我实际上正在经历一些艰难的教训。
目标是通过给定的browsenode和一些给定的项目id (ASIN)搜索csv文件(Amazon datafeed)中的一些项目。为了获得现有的物品(在我的数据库中)加上一些额外的新物品,因为不时有物品在市场上消失。我还过滤了项目的标题,因为有许多项目使用相同的标题。
我在这里读了很多技巧,最后决定使用php的fgetcsv(),并认为这个函数不会耗尽内存,因为它逐行读取文件。但是不管我怎么尝试,我总是内存不足。我不明白为什么我的代码使用这么多内存。
我设置内存限制为4096MB,时间限制为0。
服务器有64gb内存和两块SSD硬盘。可能有人请检查我的代码,并解释它是如何可能的,我运行的内存和更重要的内存是如何使用的?
private function performSearchByASINs()
{
$found = 0;
$needed = 0;
$minimum = 84;
if(is_array($this->searchASINs) && !empty($this->searchASINs))
{
$needed = count($this->searchASINs);
}
if($this->searchFeed == NULL || $this->searchFeed == '')
{
return false;
}
$csv = fopen($this->searchFeed, 'r');
if($csv)
{
$l = 0;
$title_array = array();
while(($line = fgetcsv($csv, 0, ',', '"')) !== false)
{
$header = array();
if(trim($line[6]) != '')
{
if($l == 0)
{
$header = $line;
}
else
{
$asin = $line[0];
$title = $this->prepTitleDesc($line[6]);
if(is_array($this->searchASINs)
&& !empty($this->searchASINs)
&& in_array($asin, $this->searchASINs)) //search for existing items to get them updated
{
$add = true;
if(in_array($title, $title_array))
{
$add = false;
}
if($add === true)
{
$this->itemsByASIN[$asin] = new stdClass();
foreach($header as $k => $key)
{
if(isset($line[$k]))
{
$this->itemsByASIN[$asin]->$key = trim(strip_tags($line[$k], '<br><br/><ul><li>'));
}
}
$title_array[] = $title;
$found++;
}
}
if(($line[20] == $this->bnid || $line[21] == $this->bnid)
&& count($this->itemsByKey) < $minimum
&& !isset($this->itemsByASIN[$asin])) // searching for new items
{
$add = true;
if(in_array($title, $title_array))
{
$add = false;
}
if($add === true)
{
$this->itemsByKey[$asin] = new stdClass();
foreach($header as $k => $key)
{
if(isset($line[$k]))
{
$this->itemsByKey[$asin]->$key = trim(strip_tags($line[$k], '<br><br/><ul><li>'));
}
}
$title_array[] = $title;
$found++;
}
}
}
$l++;
if($l > 200000 || $found == $minimum)
{
break;
}
}
}
fclose($csv);
}
}
我知道我的答案有点晚了,但我有一个类似的问题与fgets()
和基于fgets()的东西,如SplFileObject->current()
函数。在我的情况下,它是在windows系统上试图读取+800MB文件。我认为fgets()不会在循环中释放前一行的内存。因此,读取的每一行都留在内存中,并导致致命的内存不足错误。我使用fread($lineLength)
来修复它,但它有点棘手,因为你必须提供长度。
使用数组管理大数据而不遇到超时问题是非常困难的。相反,为什么不将这个数据feed解析到一个数据库表中,并从那里执行繁重的工作呢?
你试过吗?SplFileObject:::
<?php
$file = new SplFileObject("data.csv");
while (!$file->eof()) {
//your code here
}
?>
您正在耗尽内存,因为您使用变量,并且您从未执行unset();
并使用太多嵌套的foreach
。你可以在更多的函数中缩减代码一个解决方案应该是,使用一个真正的数据库。