0

我有一个巨大的日志文件(大约 1,000,000 行)。我想获取最后一行并使用 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);
4

1 回答 1

2

从大文件中获取和删除最后一行的最快方法是:

  1. 打开文件进行写入
  2. 寻找到最后
  3. 向后寻找一些任意缓冲区长度(比如说 1K)并读取数据以填充缓冲区
  4. 使用类似的东西向后搜索缓冲区,strrpos直到找到行尾标记¹
  5. 如果您没有找到 EOL,请转到第 3 步并重复
  6. 如果您确实找到了 EOL,则您可以根据缓冲区中的位置和从缓冲区读取的偏移量知道它发生的文件偏移量
  7. 通过寻找该偏移量并读取直到文件结束来获取最后一行²
  8. 调用ftruncate以截断从找到的行尾开始的文件部分

¹ 支持所有\n, \r,\r\n会使事情复杂化一点;特别是对于后者,它总是可能跨越两个缓冲区,因此您必须明确注意这一点。

² 这不是绝对必要的,因为您要读取的所有数据都已经通过缓冲区,因此您可以保留一份副本并节省此操作的成本。实际上,尽管最后一行不会太长,因此重新读取整个内容会更方便(C 运行时和/或 OS 文件系统缓存可能会使这变得非常快)。

这是任何程序都必须做的。如果您决定通过将前七个步骤卸载到外部实用程序来“作弊”,例如tail您可以通过一次调用从文件中删除该行ftruncate但是:如果您不想离开,在计算截断的偏移量时要小心文件中的尾随行尾字符。

于 2012-08-29T10:07:05.977 回答