2012-05-23 13 views
5

podobne do: How to read only 5 last line of the text file in PHP?PHP: Czytaj z pewnego punktu w pliku

Mam duży plik dziennika i chcę być w stanie wykazać, 100 linii z pozycji X w pliku. Potrzebuję użyć fseek zamiast file(), ponieważ plik dziennika jest zbyt duży.

Mam podobną funkcję, ale będzie czytać tylko od końca pliku. W jaki sposób można go zmodyfikować, aby można było określić pozycję początkową? Musiałbym również zacząć na końcu pliku.

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

Co staram się zrobić, to stworzyć przeglądarkę internetową opartą dziennika, który rozpocznie się od końca pliku i wyświetlać 100 linii, a po naciśnięciu przycisku „Dalej”, kolejne 100 linii poprzedzającego go będzie pokazane.

+0

Oto jeszcze więcej sposobów, aby to zrobić w kolejności wydajność: http://unix.stackexchange.com/questions/94318/awk-or-sed-efficiency#94320 – dukevin

Odpowiedz

3

Wykorzystuje to fseek do odczytu 100 wierszy pliku, począwszy od określonego przesunięcia. Jeśli przesunięcie jest większe niż liczba linii w dzienniku, odczytywanych jest pierwszych 100 linii.

W aplikacji można przejść prąd przesunięcia poprzez ciąg kwerendy dla poprzednia i następnego i portu w następnym przesunięcie na ten temat. Można również zapisać i przekazać bieżącą pozycję pliku, aby zwiększyć wydajność.

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

Jeśli liczba wierszy w pliku nie jest znana i chcę zacząć przeglądać od końca pliku, w jaki sposób mogę użyć Twojego kodu? – dukevin

+0

nevermind, polecenie linux 'wc -l my_log.log' wyświetli numery linii – dukevin

+0

Nie jestem pewien czy będziesz tego potrzebować. Jeśli przesuniesz przesunięcie większe niż liczba linii, po prostu pokazuje 100 linii na początku dziennika. 'fseek' zwraca -1, gdy próbuje szukać przeszłości. Dodam komentarz, w którym trafi on na początek pliku. – Devourant

0

zrobiłbym to jak następuje:

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

jestem nie jestem pewien, czy funkcja regex PHP może obsługiwać duży tekst. – flowfree

+0

Pewnie, że MOŻE !!!!! A przynajmniej jest znacznie szybszy niż pętle. Mam najnowszy projekt z plikiem tekstowym o wielkości 48,1 MB z ponad 500 000 linii i działa znacznie szybciej niż w przypadku pętli lub podczas takiej operacji. ale do ciebie! Dowiedz się wyrażeń regularnych i zobaczysz programowanie w inny sposób http://www.regular-expressions.info/reference.html – systrue

+0

Ponieważ użytkownik już ma problemy z pamięcią, zapisując zawartość pliku do zmiennej do analizy, a zdecydowanie szybciej, nadal będzie dużo pamięci w bardzo dużym pliku. –

1

jest mierzona w linii lub bajtów "pozycja X"? W przypadku linii, można łatwo korzystać SplFileObject dążyć do pewnej linii, a następnie odczytać 100 linii:

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

Jeśli pozycja X jest mierzona w bajtach, nie jest to prosta sprawa, zmieniając początkowy $offset = -1 do innego wartość?

+0

To fajne, ale najpierw chcę przeczytać od końca pliku. Ale długość pliku nie jest znana. – dukevin

+0

Komenda linux 'wc -l my_log.log' wyświetli # numerów linii – dukevin

3

Jeśli używasz systemu Unix, możesz użyć narzędzia sed. Na przykład: aby uzyskać wiersz 10-20 z pliku:

sed -n 10,20p errors.log 

I można to zrobić w skrypcie:

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

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

Linie są dostępne w $out tablicy.

+0

Działa to świetnie, ale chciałbym móc odczytać z końca pliku dziennika, a liczba wierszy w pliku jest nieznany – dukevin

+1

nevermind, polecenie linux 'wc -l my_log.log' wyświetli to. Twoje zdrowie! – dukevin

Powiązane problemy