在上一篇文章中,針對查詢資料表時候,php出現 “Allowed memory size of xxx bytes”的錯誤,在不修改php.ini配置的時候,用另外的函數來解決了這個問題,以犧牲部分效能的代價來換取記憶體空間,在這篇文章中,會說一下在讀取檔案的時候出現這個問題的解決思路。
在讀取檔案的時候,file_get_contents()和file()是大家慣用的兩個函數,因為操作會比較少一點,我這個地方下載了一個200M的記錄檔作為操作對象。
// 這裡是一般的寫法//$file = file_get_contents($log_file);$file = file($log_file);$start = memory_get_usage();$end = memory_get_usage();$used = $end - $start;echo $used;
無論file_get_contents還是file,都和預料中一樣,出現了錯誤”Fatal error: Allowed memory size of 134217728 bytes exhausted”。
現在我們開始看另外幾種寫法
代碼1:
這是採用fgets()每次讀取一行的結果,但是如果一行比較大的情況下,也會出現記憶體不夠用的錯誤提示
function test1($log_file) {// 記憶體:664byte// 時間:13.063009977341秒 $fp = fopen($log_file, 'r+'); while(! feof($fp)) { //$row = fgets($fp); $row = fread($fp, 2048); echo $row, "\r\n"; } fclose($fp);}
代碼2:
這裡採用了用fread()函數來控制每次讀取的資料大小,這個記憶體佔用和耗時,跟設定的每次讀取的資料大小有直接關係
function test3($log_file) {// 記憶體:656byte// 時間:9.2053289413452秒 $fp = fopen($log_file, 'r+'); while(! feof($fp)) { $row = fread($fp, 2048); //echo $row; } fclose($fp);}
代碼3:
這種方式是用過用管道的方式開啟檔案,和代碼1對比,在同使用fgets()的情況下,記憶體要比代碼1中佔用少一些。
function test2($log_file) {// 記憶體:352byte// 時間:13.38470697403秒 $cmd = "cat {$log_file} 2>&1"; $fp = popen($cmd, "r"); while(!feof($fp)) { $row = fgets($fp); echo $row, "\r\n"; } pclose($fp);}
另外還有使用fseek()函數等等,但都是在達到同一個目的,就是使得只有處理的資料讀取到記憶體中來減少記憶體佔用。
同樣也可以使用php調用系統命令方式來達到目的,這裡沒有對那種方案進行測試。
附上我測試使用的函數:
$start = memory_get_usage();$time1 = microtime(true);test3($log_file);$end = memory_get_usage();$time2 = microtime(true);$used = $end - $start;$limit = $time2 - $time1;echo "記憶體:", $used, "byte\r\n時間:", $limit, "秒\r\n";