PHP:如何读取一个不断被写入的文件

jdzmm42g  于 2023-10-15  发布在  PHP
关注(0)|答案(6)|浏览(115)

我想读取一个不断被写入的日志文件。它与应用程序驻留在同一服务器上。问题是文件每隔几秒钟就被写入一次,我基本上想实时地在应用程序上tail文件。
这可能吗?

qlzsbp2j

qlzsbp2j1#

你需要用sleep循环:

$file='/home/user/youfile.txt';
$lastpos = 0;
while (true) {
    usleep(300000); //0.3 s
    clearstatcache(false, $file);
    $len = filesize($file);
    if ($len < $lastpos) {
        //file deleted or reset
        $lastpos = $len;
    }
    elseif ($len > $lastpos) {
        $f = fopen($file, "rb");
        if ($f === false)
            die();
        fseek($f, $lastpos);
        while (!feof($f)) {
            $buffer = fread($f, 4096);
            echo $buffer;
            flush();
        }
        $lastpos = ftell($f);
        fclose($f);
    }
}

(测试过了)

tuwxkamq

tuwxkamq2#

是的,你需要在循环中睡一段时间,但你不必重新打开文件。我只是在寻找类似的问题。我想读取一个自上次读取以来可能已更改的文件。
问题是资源已到达文件结尾(EOF)。并没有继续阅读。解决方案是使用fseek($fh, ftell($fh))重置指针。
一个等待文本文件中输入的完整程序可能看起来像这样:

<?php

$fh = fopen('/var/log/system', 'r');
while (true) {
    $line = fgets($fh);
    if ($line !== false) {
      // show the line or send it via email or to a websocket..
    } else {
        // sleep for 0.1 seconds (or more?)
        usleep(0.1 * 1000000);
        fseek($fh, ftell($fh));
    }
}
j8ag8udp

j8ag8udp3#

举例来说:

$log_file = '/tmp/test/log_file.log';

$f = fopen($log_file, 'a+');
$fr = fopen($log_file, 'r' );

for ( $i = 1; $i < 10; $i++ )
{
    fprintf($f, "Line: %u\n", $i);
    sleep(2);
    echo fread($fr, 1024) . "\n";
}

fclose($fr);
fclose($f);

//Or if you want use tail

$f = fopen($log_file, 'a+');

for ( $i = 1; $i < 10; $i++ )
{
    fprintf($f, "Line: %u\n", $i);
    sleep(2);
    $result = array();
    exec( 'tail -n 1 ' . $log_file, $result );
    echo "\n".$result[0];
}

fclose($f);
nbewdwxp

nbewdwxp4#

你可以在不使用文件句柄时关闭它(一旦一部分数据被写入)。或者你可以使用一个缓冲区来存储数据,只有当它满了的时候才把它放到文件中。这样你就不会一直打开文件。
如果你想在文件被写入时就得到所有的东西,你可能需要扩展代码,写入数据,这样它也会输出到其他地方(屏幕,一些变量,其他文件.)

ldxq2e6h

ldxq2e6h5#

<?php

$fp = fopen('/var/log/syslog', 'r');// Read only
while (true) {
    $line = stream_get_line($fp, 1024 * 1024, "\n");// Full line found ? (searches for a line break)
    if ($line === false) {
        usleep(100000);// 100ms
        continue;
    }
    echo 'line:' . $line . PHP_EOL;
}
// -- Code impossible to reach --
// fclose($fp);
68bkxrlz

68bkxrlz6#

只是一个想法。
你有没有想过使用 *nix tail命令?从php中执行命令(带有一个参数,将返回一定数量的行),并在php脚本中处理结果。

相关问题