我有一个巨大的日志文件(大约1000000行)。我想获得最后一行,并使用PHP将其从文件中删除。最快的方法是什么?
我试过了:
$logfile = escapeshellarg("/path/to/logfile");
$lastline = `tail -n 1 "$logfile"`; // obtained the last line
上述方法是否足够有效?以及如何从文件中删除最后一行?
根据Jon下面的回答,以下是代码:
$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);
从大文件中获取和删除最后一行的最快方法是:
- 打开文件进行写入
- 寻找到底
- 向后查找任意缓冲区长度(比如1K)并读取数据以填充缓冲区
- 使用类似
strrpos
的东西向后搜索缓冲区,直到找到行尾标记为止 - 如果未找到EOL,请转至步骤3并重复
- 如果你确实找到了EOL,你就会知道它发生的文件偏移量,这是基于缓冲区中的位置和从中读取缓冲区的偏移量
- 通过查找该偏移量并读取直到文件结束来获得最后一行²
- 调用
ftruncate
以截断文件中从找到的行末尾开始的部分
支持所有
n
、r
和rn
会使事情复杂化小的尤其是对于后者来说,它总是可能跨越跨越两个缓冲区,所以您必须明确注意这一点。²这不是绝对必要的,因为您要访问的所有数据read已经通过了缓冲区,所以您可以保留一个复制并节省了此操作的成本。在实践中尽管最后线路不会太长,所以只要重新读取整个内容(C运行时和/或操作系统文件系统缓存可能会导致无论如何都快得愚蠢)。
这是任何程序都必须做的。如果您决定通过将前七个步骤卸载到tail
等外部实用程序来"作弊",您可以通过调用ftruncate
从文件中删除该行,但:如果您不希望在文件中留下行尾字符,则在计算截断的偏移量时要小心。