5

類似: PHP でテキスト ファイルの最後の 5 行のみを読み取る方法は?

大きなログ ファイルがあり、ファイル内の位置 X から 100 行を表示できるようにしたいと考えています。ログファイルが大きすぎるためfseekではなく、使用する必要があります。file()

同様の機能がありますが、ファイルの最後からしか読み取れません。開始位置も指定できるように変更するにはどうすればよいですか? また、ファイルの最後から開始する必要があります。

function read_line($filename, $lines, $revers = false)
{
    $offset = -1;
    $i = 0;
    $fp = @fopen($filename, "r");
    while( $lines && fseek($fp, $offset, SEEK_END) >= 0 ) {
        $c = fgetc($fp);
        if($c == "\n" || $c == "\r"){
            $lines--;
            if($revers){
                $read[$i] = strrev($read[$i]);
                $i++;
            }
        }
        if($revers) $read[$i] .= $c;
        else $read .= $c;
        $offset--;
    }
    fclose ($fp);
    if($revers){
        if($read[$i] == "\n" || $read[$i] == "\r")
            array_pop($read);
        else $read[$i] = strrev($read[$i]);
        return implode('',$read);
    }
    return strrev(rtrim($read,"\n\r"));
}

私がやろうとしているのは、ファイルの最後から開始して 100 行を表示する Web ベースのログ ビューアーを作成することです。[次へ] ボタンを押すと、その前の次の 100 行が表示されます。

4

4 に答える 4

3

これはfseek、指定されたオフセットから始まるファイルの 100 行を読み取るために使用します。オフセットがログの行数より大きい場合、最初の 100 行が読み取られます。

アプリケーションでは、 prevnextのクエリ文字列を介して現在のオフセットを渡し、それに基づいて次のオフセットを作成できます。効率を高めるために、現在のファイル位置を保存して渡すこともできます。

<?php

$GLOBALS["interval"] = 100;

read_log();

function read_log()
{
   $fp = fopen("log", "r");
   $offset = determine_offset();
   $interval = $GLOBALS["interval"];
   if (seek_to_offset($fp, $offset) != -1)
   {
      show_next_button($offset, $interval);
   }
   $lines = array();
   for ($ii = 0; $ii < $interval; $ii++)
   {
      $lines[] = trim(fgets($fp));
   }
   echo "<pre>";
   print_r(array_reverse($lines));
}

// Get the offset from the query string or default to the interval
function determine_offset()
{
   $interval = $GLOBALS["interval"];
   if (isset($_GET["offset"]))
   {
      return intval($_GET["offset"]) + $interval;
   }
   return $interval;
}

function show_next_button($offset, $interval)
{
   $next_offset = $offset + $interval;
   echo "<a href=\"?offset=" . $offset . "\">Next</a>";
}

// Seek to the end of the file, then seek backward $offset lines
function seek_to_offset($fp, $offset)
{
   fseek($fp, 0, SEEK_END);
   for ($ii = 0; $ii < $offset; $ii++)
   {
      if (seek_to_previous_line($fp) == -1)
      {
         rewind($fp);
         return -1;
      }
   }
}

// Seek backward by char until line break
function seek_to_previous_line($fp)
{
   fseek($fp, -2, SEEK_CUR);
   while (fgetc($fp) != "\n")
   {
      if (fseek($fp, -2, SEEK_CUR) == -1)
      {
         return -1;
      }
   }
}
于 2012-05-23T02:36:55.073 に答える
3

Unix を使用している場合は、このsedツールを利用できます。例: ファイルから 10 行目から 20 行目を取得するには:

 sed -n 10,20p errors.log

そして、スクリプトでこれを行うことができます:

<?php
$page  = 1;
$limit = 100;
$off   = ($page * $limit) - ($limit - 1);

exec("sed -n $off,".($limit+$off-1)."p errors.log", $out);
print_r($out);

ラインは$out配列で利用できます。

于 2012-05-23T02:30:37.323 に答える
0

「位置 X」は行単位ですか、それともバイト単位ですか? 行の場合、SplFileObject を使用して特定の行をシークし、100 行を読み取ることが簡単にできます。

$file = new SplFileObject('log.txt');
$file->seek(199); // go to line 200

for($i = 0; $i < 100 and $file->valid(); $i++, $file->next())
{
    echo $file->current();
}

位置 X がバイト単位で測定される場合、イニシャル$offset = -1を別の値に変更するのは簡単なことではありませんか?

于 2012-05-23T01:54:23.993 に答える
0

私は次のようにします:

function readFileFunc($tempFile){
    if(@!file_exists($tempFile)){
        return FALSE;
    }else{
        return file($tempFile);
    }
}
$textArray = readFileFunc('./data/yourTextfile.txt');
$slicePos = count($textArray)-101;
if($slicePos < 0){
    $slicePos = 0;  
}
$last100 = array_slice($textArray, $slicePos);
$last100 = implode('<br />', $last100);
echo $last100;
于 2012-05-23T01:04:55.583 に答える