Tengo un archivo llamado file.txt que es la actualización mediante la adición de líneas.

Estoy leyendo por este código:

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

y un gran número de líneas aparece.
Sólo quiero hacer eco de las últimas 5 líneas del archivo

¿Cómo puedo hacer eso ?


La file.txt es como este:

11111111111111
22222222222

33333333333333
44444444444

55555555555555
66666666666
InformationsquelleAutor Alireza | 2010-06-02

18 Comentarios

  1. 19

    Código no probado, pero debería funcionar:

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

    Llamar max va a manejar el archivo de menos de 6 líneas.

    • lo que si filename.txt sólo contiene 3 líneas?
    • esto es bueno , pero necesita una nota de los problemas Críticos. que es $i puede ser menor que 0; por lo que necesita este if ($i > 0) echo ….
    • No es muy bueno, ya que esto consume una gran cantidad de memoria RAM para nada en caso de que el archivo de registro es grande.
  2. 41

    Para un archivo de gran tamaño, la lectura de todas las líneas en una matriz con archivo() es un poco desperdicio. He aquí cómo usted puede leer el archivo y mantener un buffer de los últimos 5 líneas:

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

    Podría optimizar un poco más con algunas heurísticas sobre la probabilidad de longitud de la línea por la búsqueda de una posición, es decir, aproximadamente 10 líneas desde el final, y yendo más atrás si eso no ceder 5 líneas. He aquí una sencilla aplicación en la que se demuestra que:

    //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);
    • Dixon, En bucle while usted lee toda la línea y en la tienda de la última X línea. es posible leer la última X líneas?
  3. 13
    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;
    }

    Esto va a ser rápido para archivos más grandes, pero un montón de código para una tarea simple, si no hay ARCHIVOS de GRAN tamaño, el uso de este

    ReadFromEndByLine(‘myFile.txt’,6);

    • Esto requiere leer el archivo completo en la memoria, que puede ser muy malo.
    • Actualizado con un mayor bloque de código, pero aún más rápido y menos uso de memoria. – Tomado de mydebian.blogdns.org/?p=197
    • Esto debe ser aceptado respuesta.
    • El código arroja un montón de errores amigo @RobertPitt
  4. 12

    Si estás en un sistema linux se puede hacer esto:

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

    De lo contrario tendrás que contar líneas y los últimos 5, algo así como:

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

    Esta es una pregunta de la entrevista. Aquí está lo que escribí el año pasado cuando me hicieron esta pregunta. Recuerde que el código que obtiene en el Desbordamiento de la Pila es bajo licencia con el Creative Commons Compartir-Igual con la atribución requerida.

    <?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];
    }
    }

    Esta solución hace una suposición sobre la longitud máxima de la línea. El entrevistador me preguntó cómo iba a resolver el problema si no podía hacer esa suposición, y tuvieron que acomodar las líneas que fueron potencialmente más tiempo que cualquier longitud máxima elegí.

    Yo le dije que cualquier proyecto de software tiene que hacer ciertas suposiciones, pero pude probar si $c fue menor que el número deseado de las líneas, y si no lo es, fseek() más atrás de forma incremental (duplicando cada vez) hasta que obtener suficiente líneas.

  6. 6

    La mayoría de las opciones aquí supongo que para leer el archivo en la memoria y, a continuación, trabajar con filas. Esta no sería una buena idea, si el archivo es demasiado grande

    Creo que la mejor manera es utilizar algunos OS-utilidad, como ‘cola’ en unix.

    exec('tail -3 /logs/reports/2017/02-15/173606-arachni-2415.log', $output);
    echo $output;
    //2017-02-15 18:03:25 [*] Path Traversal: Analyzing response ...
    //2017-02-15 18:03:27 [*] Path Traversal: Analyzing response ...
    //2017-02-15 18:03:27 [*] Path Traversal: Analyzing response ...
    • $output es una matriz, por lo que si usted está haciendo eco a continuación, usted tendría que usar implode()
  7. 5

    Esto no utilizar file() por lo que será más eficiente para archivos de gran tamaño;

    <?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
    ?>
  8. 5

    La apertura de archivos de gran tamaño con file() puede generar una gran variedad, la reserva de una considerable cantidad de memoria.

    Puede reducir los costes de memoria con SplFileObject ya que se repite en cada línea.

    Utilizar el seek método (de seekableiterator) para leer la última línea. A continuación, usted debe restar el actual valor de la clave 5.

    Para obtener la última línea, el uso de PHP_INT_MAX. (Sí, esta es una solución.)

    $file = new SplFileObject('large_file.txt', 'r');
    $file->seek(PHP_INT_MAX);
    $last_line = $file->key();
    $lines = new LimitIterator($file, $last_line - 5, $last_line);
    print_r(iterator_to_array($lines));
    • Lo recomiendo como método rápido para archivos de gran tamaño
  9. 3

    PHP (archivo) función lee todo el archivo en una matriz.
    Esta solución requiere la menor cantidad de texto:

    $data = array_slice(file('file.txt'), -5);
    foreach ($data as $line) {
    echo $line;
    }
    • Esta es una estupenda solución! Gracias!
    • No funcionará correctamente para archivos de gran tamaño.
  10. 3

    Esta función trabajará para archivos MUY grandes en virtud de 4GB. La velocidad viene de la lectura de una gran cantidad de datos en lugar de 1 byte a la vez y contando las líneas.

    //Will seek backwards $n lines from the current position
    function seekLineBackFast($fh, $n = 1){
    $pos = ftell($fh);
    if ($pos == 0)
    return false;
    $posAtStart = $pos;
    $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);
    //check that we have indeed gone back
    if ($pos >= $posAtStart)
    return false;
    return $pos;
    }

    Después de ejecutar esta función, usted puede hacer fgets() en un bucle para leer cada línea en un momento de $fh.

  11. 1

    Aquí es el método RÁPIDO para archivos de GRAN tamaño – I desarrollar Wallace Maxters respuesta (si desea upvote – do en su respuesta) por poner su código en el interior de función práctica y agregar reversa

    function readLastLines($filename, $num, $reverse = false)
    {
    $file = new \SplFileObject($filename, 'r');
    $file->seek(PHP_INT_MAX);
    $last_line = $file->key();
    $lines = new \LimitIterator($file, $last_line - $num, $last_line);
    $arr = iterator_to_array($lines);
    if($reverse) $arr = array_reverse($arr);
    return implode('',$arr);
    }
    //use it by
    $lines = readLastLines("file.txt", 5) //return string with 5 last lines
  12. 0

    He probado este. A mí me funciona.

    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);
    ?>
  13. 0

    Menos cantidad de memoria ram, y las salidas de bien. Estoy de acuerdo con Paul Dixon…

    $lines=array();
    $fp = fopen("userlog.txt", "r");
    while(!feof($fp))
    {
    $line = fgets($fp, 4096);
    array_push($lines, $line);
    if (count($lines)>25)
    array_shift($lines);
    }
    fclose($fp);
    while ($a <= 10) {
    $a++;
    echo "<br>".$lines[$a];
    }
  14. 0

    Aquí está mi solución:

    /**
    *
    * Reads N lines from a file
    *
    * @param type $file       path
    * @param type $maxLines   Count of lines to read
    * @param type $reverse    set to true if result should be reversed.
    * @return string
    */
    public function readLinesFromFile($file, $maxLines, $reverse=false)
    {
    $lines = file($file);
    if ($reverse) {
    $lines = array_reverse($lines);
    }
    $tmpArr = array();
    if ($maxLines > count($lines))
    exit("\$maxLines ist größer als die Anzahl der Zeilen in der Datei.");
    for ($i=0; $i < $maxLines; $i++) {
    array_push($tmpArr, $lines[$i]);
    }
    if ($reverse) {
    $tmpArr = array_reverse($tmpArr);
    }
    $out = "";
    for ($i=0; $i < $maxLines; $i++) {
    $out .= $tmpArr[$i] . "</br>";
    }
    return $out;
    }
  15. -2

    Si las líneas están separadas por un CR o LF trataría la explosión de su $variable de datos:

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

    $líneas deben terminar siendo una matriz y se puede calcular el número de registros de uso de sizeof() y acaba de obtener el último 5.

    • he editado la Q, ¿Qué puedo hacer?
    • este se consume una gran cantidad de memoria RAM haciendo una enorme matriz, una gran cantidad de archivos de los casos.
    • Además, este enfoque no delimitar correctamente todos los finales de línea. Como mínimo, preg_split('/\n|\r\n?/', $data) debe ser utilizado. Pero, de nuevo, este no es el enfoque correcto para el OP del problema.
  16. -2

    esta es leer el pasado 10 de la línea de un archivo de texto

    $data = array_slice(file('logs.txt'),10);
    foreach ($data as $line) 
    {
    echo $line."<br/>";
    }

Dejar respuesta

Please enter your comment!
Please enter your name here