【问题标题】:How to truncate a file at the beginning in PHP?如何在 PHP 的开头截断文件?
【发布时间】:2025-12-01 10:25:02
【问题描述】:

我有一个用 PHP 编写的简单记录器类。它写入的文件应该有一个最大大小。我知道我可以使用ftruncate($filename, $size) 截断文件,但这会在最后删除内容。所以我想做的是:

if(filesize($filename) > $mySize) {
  //remove X bytes at BEGINNING of $filename
}

// append log message
$handle = fopen($filename, 'a+');
if($handle !== false) {
  fwrite($handle, $myMessage);
  fclose($handle);
}

这样日志会随着时间“滚动”文件,而不是无限增长(最终崩溃为 2GB,这是 PHP 的signed int 限制)。

在不必担心性能的情况下删除文件开头的最佳方法是什么?我假设将文件逐行读取到另一个缓存文件中很慢,尤其是在日志记录经常发生的情况下。有没有更好的办法?

【问题讨论】:

    标签: php file logging filesize truncate


    【解决方案1】:

    我过去为这种简单的记录器采取的方法是有一个标准的记录大小。然后,我使用该标准记录大小以及记录索引来计算写入日志记录的文件偏移量。

    通常我使用第一条记录来包含当前记录的索引,即放置下一条记录的位置,后跟逗号,然后是最大记录数。

    所以基本逻辑是

    • 检查日志文件是否存在,如果不初始化记录索引和最大索引值
    • 添加记录时,读取第一条记录以获取当前索引和最大索引
    • 计算文件偏移量和fseek()到该点并写入记录
    • 将当前索引fseek()增加到第一条记录并更新索引记录
    • 关闭文件

    主要是要有一个完整的、空格或空白填充的适当大小的记录,以便所有记录偏移量对齐,并且当您使用文本编辑器查看文件时,它都是文本。还要确保在记录末尾有一个新行以便于查看,并且每条记录在文本查看器中都位于一个新行上,无论是编辑器还是其他应用程序(例如 Web 浏览器)。

    最后,作为增量的一部分,做一个模数来强制翻转,因为你希望它是一个循环缓冲区。只需确保添加一个,因为您希望索引从 1 到 n(其中 n 是最大记录数),因为记录 0(第一条记录)用于包含当前索引和最大记录数。

    有关使用 PHP 打开、查找、写入和关闭文件的机制,请参阅PHP appending to file from specific position

    【讨论】: