2012-05-23 17 views
5

similares a: How to read only 5 last line of the text file in PHP?PHP: Leer de cierto punto en el archivo

Tengo un archivo de registro grande y quiero ser capaz de mostrar 100 líneas de posición X en el archivo. Necesito usar fseek en lugar de file() porque el archivo de registro es demasiado grande.

Tengo una función similar pero solo leerá desde el final del archivo. ¿Cómo se puede modificar para que también se pueda especificar una posición de inicio? También necesitaría comenzar al final del archivo.

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")); 
} 

Lo que estoy tratando de hacer es crear un visor de registro basado en web que comenzará desde el final del archivo y mostrar 100 líneas, y al pulsar el botón "Siguiente", los próximos 100 líneas que le precede se mostrará.

+0

Éstos son aún más maneras de hacer esto con el fin de la eficiencia: http://unix.stackexchange.com/questions/94318/awk-or-sed-efficiency#94320 – dukevin

Respuesta

3

Esto usa fseek para leer 100 líneas de un archivo a partir de un desplazamiento especificado. Si el desplazamiento es mayor que el número de líneas en el registro, se leen las primeras 100 líneas.

En su aplicación, que podría pasar el desplazamiento a través de la cadena de consulta actual para anterior y siguiente y la base de la siguiente offset sobre eso. También puede almacenar y pasar la posición actual del archivo para mayor eficiencia.

<?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; 
     } 
    } 
} 
+0

Si se desconoce el número de líneas en el archivo y deseo comenzar a verlas desde el final del archivo, ¿cómo usaré el código? – dukevin

+0

nevermind, el comando de linux 'wc -l my_log.log' dará salida a los números de línea – dukevin

+0

No estoy seguro de que lo necesite. Si pasa un desplazamiento mayor que el n. ° de líneas, esto solo muestra las 100 líneas al comienzo del registro. 'fseek' devuelve -1 cuando intenta buscar más allá del comienzo. Agregaré un comentario donde golpee el comienzo del archivo. – Devourant

0

lo haría de la siguiente manera:

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; 
+0

estoy no estoy seguro de si la función de expresiones regulares de PHP puede manejar texto grande. – flowfree

+0

Claro que PUEDE !!!!! Y al menos es mucho más rápido que los bucles. Tengo un proyecto reciente con un archivo de texto de 48.1MB con más de 500,000 líneas y funciona mucho más rápido que el bucle o mientras lo hace. pero depende de ti! Aprenda Expresiones Regulares y verá la programación de manera diferente http://www.regular-expressions.info/reference.html – systrue

+0

Como el usuario ya tiene problemas de memoria guardando los contenidos del archivo en una variable para su análisis, aunque definitivamente más rápido, aún tomará una gran cantidad de memoria en un archivo muy grande. –

1

es la "posición X" se mide en líneas o bytes? Si las líneas, puede utilizar simplemente SplFileObject a buscar a una determinada línea y luego leer 100 líneas:

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

Si la posición X se mide en bytes, no se trata de una simple cuestión de cambiar su inicial $offset = -1 a otro ¿valor?

+0

Esto es bueno, pero primero quiero leer desde el final del archivo. Pero la longitud del archivo no se conoce. – dukevin

+0

El comando de linux 'wc -l my_log.log' imprimirá el n. ° de números de línea – dukevin

3

Si está en Unix, puede utilizar la herramienta sed. Por ejemplo: para obtener la línea 10-20 de un archivo:

sed -n 10,20p errors.log 

Y usted puede hacer esto en el script:

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

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

Las líneas están disponibles en $out matriz.

+0

Esto funciona muy bien, pero me gustaría poder leer desde el final del archivo de registro, y el número de líneas en el archivo es no conocido – dukevin

+1

nevermind, el comando de linux 'wc -l my_log.log' arrojará esto. ¡Aclamaciones! – dukevin