php read large text file log

我有一个文本日志文件,大约600 MB。
我想使用php读取它并在html页面上显示数据,但是我只需要在每次运行脚本时添加的最后18行。
由于文件很大,因此无法阅读所有内容,然后按我希望的那样翻转数组。 他们是另一种方式吗?

使用fopen,filesize和fseek打开文件并仅在文件结尾附近开始读取文件。
fseek手册页上的注释包含完整的代码,可读取大文件的最后X行。

  • 你可以向后流
    $file = popen("tac $filename",'r');
    while ($line = fgets($file)) {
    echo $line;
    }
  • 将该大小的文件加载到内存中可能不是一个好主意。 这样可以解决您的问题。
    $file = escapeshellarg($file);
    $line = 'tail -n 18 '.$file;
    system($line);

记录下来,遇到了同样的问题,并在这里尝试了所有解决方案。
事实证明,达贡(Dagon)的popen" tac $filename"方式最快,而内存和CPU负载最低。
经过2Gb日志文件测试,每次读取500、1000和2000行。 光滑。 谢谢。

最好的方法是使用fread和fgets逐行读取,这非常快,因为一次只能读取一行而不是while文件:

用法示例为:

$handle = fopen("/logs/log.txt","r")
if ($handle)
{
    fseek($handle,-18,SEEK_END); //Seek to the end minus 18 lines
    while (!feof($handle))
    {
        echo fgets($handle, 4096); //Make sure your line is less that 4096, otherwise update
        $line++;
    }
    fclose($handle);
}
<?php
class Test{
  //日志路径
  const LOG_PATH="E:\phpServer\Apache\logs\error.log";
  const NGINX_LOG_PATH="E:\phpServer\\nginx\logs\error.log";
  //显示的行数
  const PAGES=50;
  public static function main(){
    header("content-type:text/html;charset=utf-8");

    if(!empty($_GET['action'])){
      self::$_GET['action']();
      exit;
    }
  }

  public static function showApacheLogs(){
    $test=new Test();
    $result=$test->readLogs(self::LOG_PATH,self::PAGES);
    $html="";
    foreach($result as $line){
      if(strpos($line,"error:")){
        $line="<font color='red'>".$line."</font>";
      }
      $html.="<div class='line'>".$line."<div>";
    }
    echo $html;
  }
  public static function showNginxLogs(){
    $test=new Test();
    $result=$test->readLogs(self::NGINX_LOG_PATH,self::PAGES);
    $html="";
    foreach($result as $line){
      if(strpos($line,"error")){
        $line="<font color='red'>".$line."</font>";
      }
      $html.="<div class='line'>".$line."<div>";
    }
    echo $html;
  }
  /**
  * 读取日志
  */
  private function readLogs($filePath,$num=20){
    $fp = fopen($filePath,"r");
    $pos = -2; 
    $eof = ""; 
    $head = false;  //当总行数小于Num时,判断是否到第一行了 
    $lines = array(); 
    while($num>0){ 
      while($eof != "\n"){ 
        if(fseek($fp, $pos, SEEK_END)==0){  //fseek成功返回0,失败返回-1 
          $eof = fgetc($fp); 
          $pos--; 
        }else{                //当到达第一行,行首时,设置$pos失败 
          fseek($fp,0,SEEK_SET); 
          $head = true;          //到达文件头部,开关打开 
          break; 
        } 

      } 
      array_unshift($lines,fgets($fp)); 
      if($head){ break; }         //这一句,只能放上一句后,因为到文件头后,把第一行读取出来再跳出整个循环 
      $eof = ""; 
      $num--; 
    } 
    fclose($fp); 
    return array_reverse($lines); 
  }
}
Test::main();
?>
<style type="text/css">
*{
  padding: 0;
  margin: 0;
}
.logsBox{
  margin:5px;
  padding: 5px;
  width: 600px;
  background: #000;
  color:#fff;
  font-size: 13px;
  float: left;
}
.logsBox .line{
  margin: 12px 0;
}
</style>
<div class="logsBox apache">
  <div class="line">日志读取...</div>
</div>
<div class="logsBox nginx">
  <div class="line">日志读取...</div>
</div>
<script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript">
  $(function(){

    function showLogs(api,showClass){
      function readLogs(){
        $.ajax({
          url:api,
          type:"get",
          dataType:"text",
          success:function(data){
            $(showClass).html(data);
          }
        });
      }
      readLogs();
      setInterval(readLogs,5000);
    }
    showLogs("?action=showNginxLogs",".nginx");
    showLogs("?action=showApacheLogs",".apache");
  });
</script>