2012-08-29 112 views
0

我有一個巨大的日誌文件(大約1,000,000行)。我想獲得最後一行,並使用PHP從文件中刪除它。最快的方法是什麼?PHP:彈出最後一行巨大的文本日誌文件

我想:

$logfile = escapeshellarg("/path/to/logfile"); 
$lastline = `tail -n 1 "$logfile"`; // obtained the last line 

足夠上述方法有效?以及如何從文件中刪除最後一行?

從下面喬恩的答案,這裏是代碼:

$buffer_size = 1000; 
$fh = fopen("/path/to/logfile", "r+"); 
fseek($fh, -$buffer_size, SEEK_END); 
$content = fgets($fh, 100); 
while(strrpos($content, PHP_EOL) != false) { 
    fseek($fh, -$buffer_size); // move backward for extra -1000 
    $content = fgets($fh, $buffer_size); 
} 
$pos_last_eol = strrpos($content, PHP_EOL); 
fseek($fh, $pos_last_eol); // seek to that position 
ftruncate($fh, ftell($fh)); 
fclose($fh); 
+2

我相信這是使用shell的正確方法,只需確保轉義輸入以避免命令行注入 – mkk

+0

同意。我加了'escapeshellarg()'。但如何有效地從文件中刪除最後一行?出於好奇: – Raptor

+0

爲什麼你需要在PHP中做到這一點?爲什麼你不能在殼裏做? – Gordon

回答

2

獲取並從一個大文件中刪除最後一行的最快方法是:

  1. 打開文件進行寫入
  2. 尋求到底
  3. 尋求一些任意的緩衝區長度倒退(比方說1K)並讀取數據以填充緩衝區
  4. 搜索緩衝向後的東西,如strrpos,直到找到最終的線的marker¹
  5. 如果你沒有找到一個EOL,轉到步驟3,重複
  6. 如果你找到一個EOL,你知道文件偏移量,它的發生基於在緩衝區中的位置,並通過尋求offset和閱讀,直到file²
  7. 呼叫ftruncate末的偏移量,緩衝從
  8. 閱讀獲取最後一行切斷部分從行尾發現文件開始

¹支持全部\n,\r,\r\n將使事情變得複雜一點;特別是對於後者,它可能總是跨越兩個緩衝區跨越 ,所以你必須明確地注意這一點。

²這不是必須的,因爲所有要進入 的數據已經通過緩衝區,因此您可以保留 副本並節省了此操作的成本。實際上,儘管最後的 行不會太長,所以更方便的是隻要 重新讀取整個事情(無論如何,C運行時和/或OS文件系統高速緩存可能會使得這個快速地變得非常快)。

這是任何程序必須做的事情。如果您決定通過將前七步卸載到外部實用程序(如tail)來「作弊」,則可以通過一次調用ftruncate,但是刪除文件中的行:在計算要截斷的偏移量時要小心不希望在文件中留下結尾行尾字符。

+0

只是以另一種方式詢問,是否更容易從文件中「彈出」第一行? – Raptor

+1

@ShivanRaptor:Popping會非常慢,因爲你必須讀取所有將「保留」的數據,並從偏移量0開始重新寫入。所有這些。 – Jon

+0

我把你的答案寫入我的問題的代碼。你能看看代碼是否工作? – Raptor