2012-05-23 11 views
5

Simile a: How to read only 5 last line of the text file in PHP?PHP: Leggere da certo punto nel file di

Ho un grande file di log e voglio essere in grado di mostrare a 100 linee da posizione X nel file. È necessario utilizzare fseek anziché file() perché il file di registro è troppo grande.

Ho una funzione simile ma leggerà solo dalla fine del file. Come può essere modificato in modo da poter specificare anche una posizione iniziale? Avrei anche bisogno di iniziare alla fine del 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")); 
} 

Quello che sto cercando di fare è creare un visualizzatore di log basato sul web che partirà dalla fine del file e visualizzare 100 linee, e quando si preme il pulsante "Avanti", i prossimi 100 linee che lo precede sarà mostrato.

+0

Qui ci sono ancora altri modi per fare questo al fine di efficienza: http://unix.stackexchange.com/questions/94318/awk-or-sed-efficiency#94320 – dukevin

risposta

3

Questo utilizza fseek per leggere 100 righe di un file a partire da un offset specificato. Se l'offset è maggiore del numero di righe nel registro, vengono lette le prime 100 righe.

Nell'applicazione, si potrebbe passare l'offset attraverso la stringa di query corrente per prev e prossimo e la base della prossima offset su questo. È inoltre possibile memorizzare e passare la posizione corrente del file per una maggiore efficienza.

<?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

Se il numero di righe nel file non è noto e voglio iniziare la visualizzazione dalla fine del file, come utilizzerei il vostro codice? – dukevin

+0

, il comando linux 'wc -l my_log.log' genererà numeri di linea – dukevin

+0

Non sono sicuro che ne avrai bisogno. Se superi un offset maggiore del numero di linee, questo mostra solo le 100 righe all'inizio del registro. 'fseek' restituisce -1 quando prova a cercare oltre l'inizio. Aggiungerò un commento nel punto in cui raggiunge l'inizio del file. – Devourant

0

lo farei come segue:

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

Sono non sono sicuro che la funzione regex di PHP possa gestire un testo di grandi dimensioni. – flowfree

+0

Sicuro che PUOI !!!!! E almeno è molto più veloce dei loop. Ho un progetto recente con un file di testo di 48.1 MB con più di 500'000 linee e funziona molto più velocemente del loop o di una cosa del genere. ma fino a te! Impara le espressioni regolari e vedrai la programmazione in modo diverso http://www.regular-expressions.info/reference.html – systrue

+0

Poiché l'utente ha già problemi di memoria, il salvataggio del contenuto del file in una variabile per l'analisi, mentre è decisamente più veloce, richiederà comunque un sacco di memoria su un file molto grande. –

1

Is "posizione X" misurata in linee o byte? Se le linee, si può facilmente utilizzare SplFileObject per cercare di una certa linea e quindi leggere 100 righe:

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

Se la posizione X viene misurata in byte, non è una semplice questione di cambiare il vostro primo $offset = -1 a un diverso valore?

+0

Questo bello, ma prima voglio leggere dalla fine del file. Ma la lunghezza del file non è nota. – dukevin

+0

Il comando linux 'wc -l mio_log.log' stamperà il numero di numeri di riga – dukevin

3

Se si utilizza Unix, è possibile utilizzare lo strumento sed. Ad esempio: per ottenere la linea 10-20 da un file:

sed -n 10,20p errors.log 

E si può fare questo nello 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); 

Le linee sono disponibili in $out array.

+0

Questo funziona benissimo, ma vorrei essere in grado di leggere dalla fine del file di registro e il numero di righe nel file è non noto – dukevin

+1

, il comando linux 'wc -l my_log.log' genererà questo risultato. Saluti! – dukevin