【问题标题】:PHP: How to read a file live that is constantly being written toPHP:如何实时读取不断写入的文件
【发布时间】:2011-03-14 05:32:52
【问题描述】:

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

这可能吗?

【问题讨论】:

    标签: php logging


    【解决方案1】:

    只是一个想法..

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

    【讨论】:

    • 你永远无法确定两次调用之间写了多少行 :)
    【解决方案2】:

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

    如果您想在写入文件后立即获取写入文件的所有内容,您可能需要扩展代码,写入数据,以便它也可以输出到其他地方(屏幕,一些变量,其他文件...)

    【讨论】:

      【解决方案3】:

      你需要用 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);
          }
      }
      

      (已测试.. 有效)

      【讨论】:

      • 页面无法加载...看起来它陷入了无限循环
      • @gAMBOOKa 尝试在回声后添加冲洗。是的,它处于无限循环中。这不是重点吗?
      【解决方案4】:

      例如:

      $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】:

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

        问题是资源已到达文件末尾 (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));
            }
        }
        

        【讨论】:

        • 我认为您不需要usleep() 声明。至少我的工作没有它。 :)
        • 但是当你有一段时间不睡觉时,它可能会导致 CPU 负载过重..
        【解决方案6】:
        <?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);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-08-07
          • 2012-09-15
          • 1970-01-01
          相关资源
          最近更新 更多