2012-11-02 11 views
2

[EDITED OP OUT這裏是短版]通過大文件循環運行的內存

通過文件循環和閱讀內容,然後寫導致函數失敗。這似乎是一個記憶問題。這是我嘗試的三個版本。

第一次嘗試這樣的:

$file = new SplFileObject($this->getDirectoryPath() . $this->getFileName(), "a+"); 
$file->setFlags(SplFileObject::DROP_NEW_LINE | SplFileObject::SKIP_EMPTY); 

if ($this->exists()) { 
    foreach ($file as $line) { 
     $tempArray = unserialize($line); 
     if ($tempArray['Key'] == $arrayOfData['Key']) { 
      foreach ($totalsToBeAdded as $key) { 
       $arrayOfData[$key] += $tempArray[$key]; 
      } 
     } 
    } 
} 

$tempString = serialize($arrayOfData); 

$file->fwrite("$tempString\r\n"); 

$this->numLines++; 

然後我嘗試這樣的:

$file = new SplFileObject($this->getDirectoryPath() . $this->getFileName(), "a+"); 
$file->setFlags(SplFileObject::DROP_NEW_LINE | SplFileObject::SKIP_EMPTY); 

if ($this->exists()) { 
    while (!$file->eof()) { 
     $tempArray = unserialize($file->current()); 
     if ($tempArray['PartNumber'] == $arrayOfData['PartNumber']) { 
      foreach ($totalsToBeAdded as $key) { 
       $arrayOfData[$key] += $tempArray[$key]; 
      } 
     } 

     $file->next(); 
    } 
} 

$tempString = serialize($arrayOfData); 

$file->fwrite("$tempString\r\n"); 

$this->numLines++; 

最後我放棄了SplFileObject,只是正常的fopen等去:

$handle = fopen($this->getDirectoryPath() . $this->getFileName(), "a+"); 

if ($this->exists()) { 
    while (false !== ($line = fgets($handle))) { 
     $tempArray = unserialize(trim($line)); 
     if ($tempArray['Key'] == $arrayOfData['Key']) { 
      foreach ($totalsToBeAdded as $key) { 
       $arrayOfData[$key] += $tempArray[$key]; 
      } 
     } 
    } 
} 

$tempString = serialize($arrayOfData); 
fwrite($handle, "$tempString\r\n"); 
fclose($handle); 
$this->numLines++; 

編輯MORE信息:

我很好奇,PHP的底層代碼在逐行掃描文件時使用了迭代器數組,這可能會導致它無法使用。

此外,該文件確實開始建設,我可以看它寫,直到它達到約500-600k,然後它死亡。

最終文件大小將在10mb左右。

最後一個更新:

這工作(通知缺乏的開通和閱讀文件):

public function writeUnique($arrayOfData, $totalsToBeAdded) { 
     $tempArray = array(); 

     $handle = fopen($this->fullPath, "a+"); 

     $tempString = serialize($arrayOfData); 
     fwrite($handle, "$tempString\r\n"); 
     fclose($handle); 
     $this->numLines++; 
} 

這枚符(注意所有正在做的是在整個文件中循環再寫該文件):

public function writeUnique($arrayOfData, $totalsToBeAdded) { 
     $tempArray = array(); 

     $handle = fopen($this->fullPath, "a+"); 

     if ($this->exists()) { 
      while (false !== ($line = fgets($handle))) { 

      } 
     } 

     $tempString = serialize($arrayOfData); 
     fwrite($handle, "$tempString\r\n"); 
     fclose($handle); 
     $this->numLines++; 
} 

更新三:

我現在測試了這一點:

public function writeUnique($arrayOfData, $totalsToBeAdded) { 

    $handle = fopen($this->fullPath, "a+"); 

    if ($this->exists()) { 
     while (false !== ($line = fgets($handle))) { 

     } 
    } 

    $tempString = serialize($arrayOfData); 
//  fwrite($handle, "$tempString\r\n"); Commented out the writing. 
    fclose($handle); 
    $this->numLines++; 
} 

這工作。沒有失敗,內存錯誤或其他明智的。

因此,它似乎是重讀大文件的相同行的迭代的問題,或者函數的寫部分以某種方式踩在讀函數的腳趾上......老實說,沒有道理。我知道每個人都認爲它與我的陣列有關。但是我已經拿出了很多我的邏輯,我只是​​想讀/寫一個大文件。

+0

'trime($ line)'是一個錯字,你的意思是'trim'或者它是你自定義的函數嗎?顯然PHP沒有'trime()'函數 –

+0

http://stackoverflow.com/questions/2461762/force-freeing-memory-in-php –

+0

非你的例子顯示$ arrayOfData或$ totalsToBeAdded變量來自哪裏。我懷疑當你解析這個文件時,你會不斷地加入這些變量並最終耗盡空間? –

回答

0

所以,我終於崩潰了,做數學要弄清楚我多少圈需要PHP來完成這個文件,而且數量8,788,338,000,000倍。

這反過來導致PHP超時。爲了防止它需要添加這行代碼。

set_time_limit(0); // ignore php timeout 

現在可以逐行讀取和解析臨時文件。但是,在大文件(10 MB +)上,到目前爲止,完成該功能的時間已經超過一個小時了(它仍在運行,因爲我可以看到臨時文件變大了)。

我已經認識到,如果速度是關鍵,那麼將大型數據集存儲到臨時SQL表中可能會更好。這對我來說不是一種選擇,但現在我正在強制允許這個問題。最壞的情況下,這將至少允許它運行。

被警告:這將使無限循環無法運行,並可能會導致服務器死機。請確保您知道如何在嘗試之前通過UNIX殺死進程。

0

嘗試:

if ($this->exists()) { 
    while (false !== ($line = fgets($handle))) { 
     $tempArray = unserialize(trim($line)); 
     unset($line); 
     if ($tempArray['Key'] == $arrayOfData['Key']) { 
      foreach ($totalsToBeAdded as $key) { 
       $arrayOfData[$key] += $tempArray[$key]; 
      } 
     } 
     unset($tempArray); 
    } 
} 

唯一持久的陣列,我可以在這裏看到$totalsToBeAdded$arrayOfData,這看起來是一維的從你的+=操作,所以沒有什麼可以做,但微優化。

+0

我以爲也是這樣,除了$ totalsToBeAdded只是硬編碼'$ totalsToBeAdded = array('stuff','stuff'等);'那裏只有9件物品。 – defaultNINJA

+0

嘗試取消設置命令。沒有幫助。謝謝你的想法。 – defaultNINJA