2009-08-10 61 views
1

我試圖讀取一些大文本文件(50M-200M之間),做簡單的文本替換(本質上我有幾個沒有正確逃脫的XML,正常情況下)。下面是功能的簡化版本:在失敗之前用PHP解析大文本文件而不殺服務器

<?php 
function cleanFile($file1, $file2) { 
$input_file  = fopen($file1, "r"); 
$output_file = fopen($file2, "w"); 
    while (!feof($input_file)) { 
    $buffer = trim(fgets($input_file, 4096)); 
    if (substr($buffer,0, 6) == '<text>' AND substr($buffer,0, 15) != '<text><![CDATA[') 
    { 
     $buffer = str_replace('<text>', '<text><![CDATA[', $buffer); 
     $buffer = str_replace('</text>', ']]></text>', $buffer); 
    } 
    fputs($output_file, $buffer . "\n"); 
    } 
    fclose($input_file); 
    fclose($output_file);  
} 
?> 

我不明白的是,對於大文件,150MB左右,PHP內存使用熄滅圖表(約2GB)。我認爲這是閱讀大文件的最有效的內存方式。有沒有一些方法可以提高記憶效率?也許有些設置會在應該收集內容時保存在內存中?

換句話說,它不工作,我不知道爲什麼,據我所知我沒有做錯事。任何方向爲我去?感謝您的任何意見。

+0

看看http://stackoverflow.com/questions/1176589/optimizing-php-command-line-scripts-to-process-large-flat-files – ftrotter 2010-08-23 08:16:58

回答

2

PHP並不是真正爲此設計的。將工作卸載到不同的進程並調用它或從PHP啓動它。我建議使用PythonPerl

+0

不幸的是,這不是一個選擇在這一點上選擇另一種語言。 :( – jacobangel 2009-08-10 14:22:53

+2

然後在一個單獨的過程中使用PHP來實現它,關鍵是你不應該把這個大文件解析爲你的請求的一部分,你應該在一個單獨的過程中卸載工作,返回一個響應,然後允許第二次請求確定進程ID是否完成異步FTW – Randolpho 2009-08-10 14:42:38

+0

同意我的猜測是你通過ftp,批處理等接收文件爲什麼不立即解析文件,而是在文件系統登陸時立即解析文件等待有人把它從web請求中拉下來 – 2009-08-10 16:25:34

1

從我的PHP的垃圾回收的微薄理解,下面可能會有所幫助:

  1. unset$buffer當你寫完它到磁盤上,明確地告訴GC把它清理乾淨。
  2. if塊放入另一個函數中,以便GC在該函數退出時運行。

這些建議背後的推理是我懷疑垃圾收集器沒有釋放內存,因爲一切都在單個函數內完成,GC是垃圾。

+0

試過這個。它釋放了一些內存,但還不夠。我希望我知道它在內存中究竟做了什麼。 – jacobangel 2009-08-10 21:37:38

0

我預計這在很多情況下會失敗。您正在讀取4096個字節的數據塊。誰知道截止日期不會在<text>的中間?在這種情況下,您的str_replace不起作用。

你有沒有考慮過使用正則表達式?