我不知道如何措辞,所以我将其输入,然后编辑并回答出现的任何问题..
目前在我的本地网络设备(基于 PHP4)上,我正在使用它来跟踪实时系统日志文件:http ://commavee.com/2007/04/13/ajax-logfile-tailer-viewer/
这很好用,它每 1 秒加载一个外部页面 (logfile.php),该页面执行一个tail -n 100 logfile.log
脚本不做任何缓冲,因此它显示在屏幕上的结果是日志文件的最后 100 行。
logfile.php 包含:
<? // logtail.php $cmd = "tail -10 /path/to/your/logs/some.log"; exec("$cmd 2>&1", $output);
foreach($output as $outputline) {
echo ("$outputline\n");
}
?>
这部分运作良好。
我已经调整了 logfile.php 页面以将 $outputline 写入新的文本文件,只需使用fwrite($fp,$outputline."\n");
虽然这可行,但我在创建的新文件中遇到了重复问题。
显然,每次运行 tail -n 100 都会产生结果,下一次运行时它可能会产生一些相同的行,因为这种重复我最终会在新文本文件中出现多行重复。
我不能直接比较我要写的行和前面的行,因为可能有相同的匹配。
有什么办法可以将当前的 100 行块与前一个块进行比较,然后只写不匹配的行。块 A 和 B 将包含所需的相同行再次可能的问题...
是否可以更新 logfile.php 以记录它最后在我的日志文件中的位置,然后只从那里读取接下来的 100 行并将它们写入新文件?
日志文件可能高达 500MB,所以我不想每次都阅读它。
欢迎任何意见或建议..
谢谢
更新@ 16:30
我有点让这个工作使用:
$file = "/logs/syst.log";
$handle = fopen($file, "r");
if(isset($_SESSION['ftell'])) {
clearstatcache();
fseek($handle, $_SESSION['ftell']);
while ($buffer = fgets($handle)) {
echo $buffer."<br/>";
@ob_flush(); @flush();
}
fclose($handle);
@$_SESSION['ftell'] = ftell($handle);
} else {
fseek($handle, -1024, SEEK_END);
fclose($handle);
@$_SESSION['ftell'] = ftell($handle);
}
这似乎可行,但它首先加载整个文件,然后才加载更新。
我如何从最后 50 行开始,然后只是更新?
谢谢 :)
更新 2013年 4 月 6 日 虽然这可行,但对于大文件来说速度很慢。
我试过这段代码,它似乎更快,但它不只是从它停止的地方读取。
function last_lines($path, $line_count, $block_size = 512){
$lines = array();
// we will always have a fragment of a non-complete line
// keep this in here till we have our next entire line.
$leftover = "";
$fh = fopen($path, 'r');
// go to the end of the file
fseek($fh, 0, SEEK_END);
do{
// need to know whether we can actually go back
// $block_size bytes
$can_read = $block_size;
if(ftell($fh) < $block_size){
$can_read = ftell($fh);
}
// go back as many bytes as we can
// read them to $data and then move the file pointer
// back to where we were.
fseek($fh, -$can_read, SEEK_CUR);
$data = fread($fh, $can_read);
$data .= $leftover;
fseek($fh, -$can_read, SEEK_CUR);
// split lines by \n. Then reverse them,
// now the last line is most likely not a complete
// line which is why we do not directly add it, but
// append it to the data read the next time.
$split_data = array_reverse(explode("\n", $data));
$new_lines = array_slice($split_data, 0, -1);
$lines = array_merge($lines, $new_lines);
$leftover = $split_data[count($split_data) - 1];
}
while(count($lines) < $line_count && ftell($fh) != 0);
if(ftell($fh) == 0){
$lines[] = $leftover;
}
fclose($fh);
// Usually, we will read too many lines, correct that here.
return array_slice($lines, 0, $line_count);
}
任何方式都可以修改它,以便从最后一个已知位置读取..?
谢谢