代码之家  ›  专栏  ›  技术社区  ›  HyderA

php:如何实时读取不断被写入的文件

  •  10
  • HyderA  · 技术社区  · 16 年前

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

    这有可能吗?

    5 回复  |  直到 7 年前
        1
  •  21
  •   Jester    11 年前

    你需要睡眠循环:

    $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);
        }
    }
    

    (测试)它起作用了)

        2
  •  2
  •   iRaS    7 年前

    是的,您需要在循环中睡眠一段时间,但不必重新打开文件。我只是在找一个类似的问题。我想读一个自上次读到之后可能已经被更改的文件。

    问题是资源已到达文件结尾( 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));
        }
    }
    
        3
  •  0
  •   Sergey Eremin    16 年前

    如果不使用文件句柄(一旦写入了一部分数据),则可以将其关闭。或者,您可以使用缓冲区来存储数据,并仅在数据已满时将其放到文件中。这样你就不会一直打开文件了。

    如果您希望在文件写入后立即获得写入该文件的所有内容,则可能需要扩展代码,写入数据,以便它也输出到其他位置(屏幕、某个变量、其他文件…)

        4
  •  0
  •   Artefacto    16 年前

    例如:

    $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);
    
        5
  •  -1
  •   Andreas    16 年前

    只是一个想法…

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

    推荐文章