早上好, 实际上,我在尝试处理高达 4GB 的巨大 csv 文件时经历了一些惨痛的教训。
目标是通过给定的浏览节点以及某些给定的商品 ID (ASIN) 搜索 csv 文件(亚马逊数据源)中的某些商品。为了混合现有的元素(在我的数据库中)加上一些额外的新元素,因为有时元素会在市场上消失。我还过滤了项目的标题,因为有很多项目使用相同的标题。
我在这里阅读了很多 af 提示,最后决定使用 php 的 fgetcsv() 并认为该函数不会耗尽内存,因为它会逐行读取文件。 但无论我尝试什么,我总是内存不足。 我不明白为什么我的代码使用这么多内存。
我将内存限制设置为4096MB,时间限制为0。服务器有64 GB RAM和两个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)
修复了它,但它有点棘手,因为您必须提供长度。
关于php - 使用 php fgetcsv 读取巨大的 CSV 文件时遇到问题 - 了解内存消耗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32622521/