PHP metin dosyasının sadece 5 son satırı nasıl okunur?

11 Cevap php

I have a file named "file.txt" it updates by adding lines to it.

Bu kod ile bunu okuyorum:

$fp = fopen("file.txt", "r");
$data = "";
while(!feof($fp))
{
$data .= fgets($fp, 4096);
}
echo $data;

and a huge number of lines appears. I just want to echo the last 5 lines of the file

Bunu nasıl yapabilirim?


edit: @ Alistair

dosya.txt bu gibi

1111111111111122222222222

3333333333333344444444444

5555555555555566666666666

11 Cevap

Denenmemiş kodu, ama çalışması gerekir:

$file = file("filename.txt");
for ($i = count($file)-6; $i < count($file); $i++) {
  echo $file[$i] . "\n";
}

Bu hile yapar yürütmem. Gerçek kodunda da kontrol etmelisiniz count($file) emin en az beş satır var yapmak, hataları önlemek için.

Büyük bir dosya için, dosya ile bir dizi () içine tüm satırları okurken biraz savurgan olduğunu. Burada dosyayı okumak ve son 5 satırlık bir tampon korumak nasıl bulunuyor:

$lines=array();
$fp = fopen("file.txt", "r");
while(!feof($fp))
{
   $line = fgets($fp, 4096);
   array_push($lines, $line);
   if (count($lines)>5)
       array_shift($lines);
}
fclose($fp);

Sen sonundan itibaren yaklaşık 10 satır bir pozisyonda, diyelim ki, isteyen, ve bu 5 satır verim vermezse geri ileri giderek olası hat uzunluğu hakkında bazı sezgisel tarama ile biraz daha bu optimize olabilir. İşte o gösteren basit bir uygulama var:

//how many lines?
$linecount=5;

//what's a typical line length?
$length=40;

//which file?
$file="test.txt";

//we double the offset factor on each iteration
//if our first guess at the file offset doesn't
//yield $linecount lines
$offset_factor=1;


$bytes=filesize($file);

$fp = fopen($file, "r") or die("Can't open $file");


$complete=false;
while (!$complete)
{
    //seek to a position close to end of file
    $offset = $linecount * $length * $offset_factor;
    fseek($fp, -$offset, SEEK_END);


    //we might seek mid-line, so read partial line
    //if our offset means we're reading the whole file, 
    //we don't skip...
    if ($offset<$bytes)
        fgets($fp);

    //read all following lines, store last x
    $lines=array();
    while(!feof($fp))
    {
        $line = fgets($fp);
        array_push($lines, $line);
        if (count($lines)>$linecount)
        {
            array_shift($lines);
            $complete=true;
        }
    }

    //if we read the whole file, we're done, even if we
    //don't have enough lines
    if ($offset>=$bytes)
        $complete=true;
    else
        $offset_factor*=2; //otherwise let's seek even further back

}
fclose($fp);

var_dump($lines);
function ReadFromEndByLine($filename,$lines)
{

        /* freely customisable number of lines read per time*/
        $bufferlength = 5000;

        $handle = @fopen($filename, "r");
        if (!$handle) {
                echo "Error: can't find or open $filename<br/>\n";
                return -1;
        }

        /*get the file size with a trick*/
        fseek($handle, 0, SEEK_END);
        $filesize = ftell($handle);

        /*don't want to get past the start-of-file*/
        $position= - min($bufferlength,$filesize);

        while ($lines > 0) {

                if ($err=fseek($handle,$position,SEEK_END)) {  /* should not happen but it's better if we check it*/
                        echo "Error $err: something went wrong<br/>\n";
                        fclose($handle);
                        return $lines;
                }

                /* big read*/
                $buffer = fread($handle,$bufferlength);

                /* small split*/
                $tmp = explode("\n",$buffer);

                /*previous read could have stored a partial line in $aliq*/
                if ($aliq != "") {

                                /*concatenate current last line with the piece left from the previous read*/
                                $tmp[count($tmp)-1].=$aliq;
                }

                /*drop first line because it may not be complete*/
                $aliq = array_shift($tmp);

                $read = count($tmp);
                if ( $read >= $lines ) {   /*have read too much!*/

                        $tmp2 = array_slice($tmp,$read-$n);
                        /* merge it with the array which will be returned by the function*/
                        $lines = array_merge($tmp2,$lines);

                        /* break the cycle*/
                        $lines = 0;
                } elseif (-$position >= $filesize) {  /* haven't read enough but arrived at the start of file*/

                        //get back $aliq which contains the very first line of the file
                        $lines = array_merge($aliq,$tmp,$lines);

                        //force it to stop reading
                        $lines = 0;

                } else {              /*continue reading...*/

                        //add the freshly grabbed lines on top of the others
                        $lines = array_merge($tmp,$lines);

                        $lines -= $read;

                        //next time we want to read another block
                        $position -= $bufferlength;

                        //don't want to get past the start of file
                        $position = max($position, -$filesize);
                }
        }
        fclose($handle);

        return $lines;
}

Orada BÜYÜK DOSYA, bu kullanırsanız, bu, basit bir görev için büyük dosyaları ama kodun çok hızlı olacak

ReadFromEndByLine ('myfile.txt', 6);

Bu ortak bir röportaj sorudur. İşte bu soruyu sordu ben geçen sene ne yazdı bulunuyor. Yığın taşması olsun kod attribution required ile Creative Commons Share-Alike ile lisanslı olduğunu unutmayın.

<?php

/**
 * Demonstrate an efficient way to search the last 100 lines of a file
 * containing roughly ten million lines for a sample string. This should
 * function without having to process each line of the file (and without making
 * use of the “tail” command or any external system commands). 
 */

$filename = '/opt/local/apache2/logs/karwin-access_log';
$searchString = 'index.php';
$numLines = 100;
$maxLineLength = 200;

$fp = fopen($filename, 'r');

$data = fseek($fp, -($numLines * $maxLineLength), SEEK_END);

$lines = array();
while (!feof($fp)) {
  $lines[] = fgets($fp);
}

$c = count($lines);
$i = $c >= $numLines? $c-$numLines: 0;
for (; $i<$c; ++$i) {
  if ($pos = strpos($lines[$i], $searchString)) {
    echo $lines[$i];
  }
}

Bu çözüm maksimum hat uzunluğu hakkında bir varsayım yapmak yok. Görüşmeci bu varsayımı gelemedi ben sorunu çözmek nasıl sordu, ve artık ben seçtim herhangi max uzunluğundan daha potansiyel vardı hatları karşılamak zorunda kaldı.

Lütfen daha da değilse, fseek() Ben herhangi bir yazılım projesi belli varsayımlar yapmak zorunda olduğunu söyledim, ama $c çizgilerin istenen sayısından daha az ise ben test edebilir, ve Yeterince çizgiler yapmak kadar aşamalı olarak (her zaman iki katına).

Bu kullanmak değil file() bu yüzden büyük dosyalar için daha verimli olacaktır;

<?php
function read_backward_line($filename, $lines, $revers = false)
{
    $offset = -1;
    $c = '';
    $read = '';
    $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"));
}
//if $revers=false function return->
//line 1000: i am line of 1000
//line 1001: and i am line of 1001
//line 1002: and i am last line
//but if $revers=true function return->
//line 1002: and i am last line
//line 1001: and i am line of 1001
//line 1000: i am line of 1000
?>

Eğer bir linux sistemde iseniz bunu yapabilirsiniz:

$lines = `tail -5 /path/to/file.txt`;

Aksi takdirde satırları saymak ve bir şey gibi, son 5 almak gerekir:

$all_lines = file('file.txt');
$last_5 = array_slice($all_lines , -5);

Bu fonksiyon, 4GB altında GERÇEKTEN büyük dosyalar için çalışacaktır. Hızı bir anda yerine 1 bayt veri büyük bir yığın okuma ve hatları sayma geliyor.

// Will seek backwards $n lines from the current position
function seekLineBackFast($fh, $n = 1){
        if(ftell($fh) == 0)
                return false;

        $readSize = 2048*2;
        $pos = ftell($fh);
        if(!$pos){
                fseek($fh, 0, SEEK_SET);
                return false;
        }
        // we want to seek 1 line before the line we want.
        // so that we can start at the very beginning of the line
        while ($n >= 0) {
                if($pos == 0)
                        break;
                $pos -= $readSize;
                if($pos <= 0){
                        $pos = 0;
                }

                // fseek returns 0 on success and -1 on error
                if(fseek($fh, $pos, SEEK_SET)==-1){
                        fseek($fh, 0, SEEK_SET);
                        break;
                }
                $data = fread($fh, $readSize);
                $count = substr_count($data, "\n");
                $n -= $count;

                if($n < 0)
                        break;
        }
        fseek($fh, $pos, SEEK_SET);
        // we may have seeked too far back
        // so we read one line at a time forward
        while($n < 0){
                fgets($fh);
                $n++;
        }
        // just in case?
        $pos = ftell($fh);
        if(!$pos)
                fseek($fh, 0, SEEK_SET);
        return $pos;
}

Yukarıdaki fonksiyon çalıştırdıktan sonra, sadece $ fh bir anda her satırı okumak için bir döngü içinde fgets () yapabilirsiniz.

Ben bunu test ettik. Bu benim için çalışıyor.

function getlast($filename,$linenum_to_read,$linelength){

   // this function takes 3 arguments;


   if (!$linelength){ $linelength = 600;}
$f = fopen($filename, 'r');
$linenum = filesize($filename)/$linelength;

    for ($i=1; $i<=($linenum-$linenum_to_read);$i++) {
    $data = fread($f,$linelength);
    }
echo "<pre>";       
    for ($j=1; $j<=$linenum_to_read+1;$j++) {
    echo fread($f,$linelength);
    }

echo "</pre><hr />The filesize is:".filesize("$filename");
}

getlast("file.txt",6,230);


?>

Çizginizi bir CR veya LF tarafından ayrılmış iseniz exploding sizin $ veri değişkeni denemek istiyorum:

$lines = explode("\n", $data);

$ Çizgiler bir dizi olarak bitirmek gerekir ve sizeof kullanarak kayıtların sayısını çalışabilir () ve sadece son 5 olsun.

Sen benim küçük yardımcı kitaplığını (2 fonksiyonlar) kullanabilirsiniz

https://github.com/jasir/file-helpers

Sonra sadece kullanın:

//read last 5 lines
$lines = \jasir\FileHelpers\FileHelpers::readLastLines($pathToFile, 5);

Bu metin dosyasının son 10 satırı okunur

$data = array_slice(file('logs.txt'),10);

    foreach ($data as $line) 

    {

        echo $line."<br/>";
    }