2010-04-08 6 views
7

Mam plik 200kb, co używam na wielu stronach, ale na każdej stronie potrzebuję tylko 1-2 linii tego pliku, więc jak mogę odczytać tylko te linie, co jest potrzebne, jeśli znam numer wiersza?Jak zapisać pamięć podczas odczytu pliku na Php?

Na przykład, jeśli potrzebuję tylko dziesiątej linii, nie chcę ładować do pamięci wszystkich linii, tylko do dziesiątej linii.

Przepraszamy za mój zły angielski!

Odpowiedz

3

Jeśli nie znasz przesunięcia linii, musisz przeczytać każdą linię aż do tego punktu. Możesz po prostu wyrzucić stare linie (których nie chcesz), przechodząc przez plik z czymś takim, jak fgets(). (EDIT: Zamiast fgets(), chciałbym zasugerować @Gordon „s solution)

Być może lepszym rozwiązaniem byłoby wykorzystanie bazy danych, jak silnik bazy danych będzie wykonywać pracę grunt przechowywania strun i pozwalają na (bardzo skutecznie) uzyskać pewną "linię" (nie byłaby to linia, ale rekord z identyfikatorem numerycznym, jednak jest to równoznaczne z tym samym) bez konieczności czytania rekordów przed nim.

+0

Proszę skomentować downwardem – Yacoby

+0

Baza będzie szybsza, subiektywna. Jeśli informacje, do których próbuje uzyskać dostęp znajdują się na początku pliku, będzie o wiele szybciej. Czytanie z bazy danych wciąż czyta z pliku. Poprawi on indeks bazy danych tylko wtedy, gdy szuka czegoś od początku jego pliku. Zależy to również od tego, co dokładnie próbuje osiągnąć. –

+2

Nigdy nie powiedział, że baza danych będzie szybsza. Tyle tylko, że byłoby lepiej. Obawy PO można postrzegać raczej jako kwestię pamięci niż prędkości. – webbiedave

0

Wystarczy przechodzić przez nie bez zapisywania, np.

$i = 1; 
$file = fopen('file.txt', 'r'); 
while (!feof($file)) { 
    $line = fgets($file); // this gets whole line from the file; 
    if ($i == 10) { 
     break; // break on tenth line 
    } 
    $i ++; 
} 

Powyższy przykład zachowałby pamięć tylko dla ostatniej linii, którą dostał z pliku, więc jest to najbardziej wydajna pamięć, aby to zrobić.

+1

1. zapomniałeś $ i ++, 2. dlaczego nie sprawdzić, czy $ i == 10? – zerkms

+0

Bleh, zawsze zapominam wstawiać przyrosty. Jeśli chodzi o == 10 ... znowu, zły nawyk parsowania zbyt wielu rzeczy z powtórzeniami ... Naprawdę przepraszam, naprawiono :) – bisko

+0

stream_get_line() jest szybszy niż fgets() –

0

użyć fgets(). 10 razy :-) w tym przypadku nie zachowasz wszystkich 10 linii w pamięci

1
<?php 
    $lines = array(1, 2, 10); 

    $handle = @fopen("/tmp/inputfile.txt", "r"); 
    if ($handle) { 
     $i = 0; 
     while (!feof($handle)) { 
      $line = stream_get_line($handle, 1000000, "\n"); 

      if (in_array($i, $lines)) { 
       echo $line; 
          $line = ''; // Don't forget to clean the buffer! 
      } 

      if ($i > end($lines)) { 
       break; 
      } 

      $i++; 
     } 
     fclose($handle); 
    } 
?> 
19

Spróbuj SplFileObject

echo memory_get_usage(), PHP_EOL;  // 333200 

$file = new SplFileObject('bible.txt'); // 996kb 
$file->seek(5000);      // jump to line 5000 (zero-based) 
echo $file->current(), PHP_EOL;   // output current line 

echo memory_get_usage(), PHP_EOL;  // 342984 vs 3319864 when using file() 

do wyprowadzania bieżącą linię, można użyć current() czy tylko echo $file. Uważam, że użycie metody jest jaśniejsze. Możesz także użyć fgets(), ale to dostanie następny wiersz.

Oczywiście potrzebujesz tylko środkowych trzech linii. Dodałem telefony memory_get_usage tylko po to, aby udowodnić, że takie podejście nie ma prawie żadnej pamięci.

+0

Nice. Nie zauważyłem, że 'seek' był oparty na linii, a nie na bajcie. – Yacoby

+0

+1 Preferuję ten kod, ponieważ jest to po prostu mniej pracy dla programisty, i jest jaśniejsze, co się dzieje (szukając pewnej linii) niż 'fgets'. – notJim

+0

@Yakie istnieje 'SplFileInfo :: fseek()' i 'SplFileInfo :: seek()'. Ta druga jest oparta na liniach, druga jest oparta na bajtach. 'seek()' jest metodą z interfejsu 'SeekableIterator'. – Gordon

0

Dlaczego próbujesz załadować tylko pierwsze dziesięć linii? Czy wiesz, że ładowanie wszystkich tych linii jest w rzeczywistości problemem?

Jeśli nie mierzysz, to nie wiesz, że to problem. Nie marnuj swojego czasu na optymalizację bez problemów. Jest szansa, że ​​jakakolwiek zmiana wydajności, która nie spowoduje załadowania całego pliku 200K, będzie niezauważalna, chyba że wiesz, że załadowanie tego pliku jest rzeczywiście wąskim gardłem.

2

Czy zmienia się zawartość pliku? Jeśli jest statyczny lub stosunkowo statyczny, możesz utworzyć listę przesunięć, w których chcesz odczytać dane. Na przykład, jeżeli zmiany plik raz w roku, ale trzeba ją przeczytać setki razy dziennie, to można wstępnie obliczyć przesunięcia linii chcesz i przejść bezpośrednio do nich tak:

$offsets = array(); 
while ($line = fread($filehandle)) { .... find line 10 .... } 
$offsets[10] = ftell($filehandle); // store line 10's location 
.... find next line 
$offsets[20] = ftell($filehandle); 

i wkrótce. Następnie możesz trywialnie przeskoczyć do lokalizacji tej linii:

$fh = fopen('file.txt', 'rb'); 
fseek($fh, $offsets[20]); // jump to line 20 

Ale to może być całkowita przesada.Spróbuj przetestować operacje - porównaj czas potrzebny na wykonanie staroświeckiego "odczytu 20 linii" w porównaniu z prekompute/jump.