2012-08-29 72 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