2010-07-03 11 views
10

Czytam plik zawierający około 50k linii przy użyciu funkcji file() w PHP. Jednak jego błąd braku pamięci, ponieważ zawartość pliku są przechowywane w pamięci jako tablicy. Czy jest jakiś inny sposób?Najmniejszy sposób na odczyt pamięci w PHP

Ponadto długości zapisanych linii są zmienne.

Oto kod. Również plik ma wartość 700kB, a nie mB.

private static function readScoreFile($scoreFile) 
{ 
    $file = file($scoreFile); 
    $relations = array(); 

    for($i = 1; $i < count($file); $i++) 
    { 
     $relation = explode("\t",trim($file[$i])); 
     $relation = array(
         'pwId_1' => $relation[0], 
         'pwId_2' => $relation[1], 
         'score' => $relation[2], 
         ); 
     if($relation['score'] > 0) 
     { 
      $relations[] = $relation; 
     } 
    } 

    unset($file); 
    return $relations; 
} 
+0

Wiem, że to pytanie jest stary, ale dwie rzeczy tutaj. 1. przeczytaj plik wiersz po linii. 2. Błąd braku pamięci może polegać na tym, że przechowujesz wszystko również w tablicy, zazwyczaj nie jest to dobry pomysł bez jakiejś kontroli i wiedzy o pamięci, którą masz – Atherion

Odpowiedz

13

Zastosowanie fopen, fread i fclose czytać kolejno pliku:

$handle = fopen($filename, 'r'); 
if ($handle) { 
    while (!feof($handle)) { 
     echo fread($handle, 8192); 
    } 
    fclose($handle); 
} 
+0

to nie działa, chcę czytać wiersz po wierszu.Powracające linie mutliple na każdym fidzie (domyślam się 8192 bajtów) – Chetan

+7

zamieniają fread na "fgets": fgets - Pobiera linię ze wskaźnika pliku –

+0

Możesz użyć pośredniej zmiennej $ line do przechowywania bajtów każdej linii, a następnie echo $ line . fread jest prawdopodobnie jednym z najbardziej wydajnych sposobów przesyłania pliku, więc przeczytaj wyniki fread (i dołącz do $ line), aż znajdziesz line break. Następnie wykonaj, co chcesz z tą linią, a następnie ustaw $ line = "" i wznów dołączanie wyników rewizji do $ line. – luiscubal

9

EDIT po aktualizacji pytanie comments to answer of fabjoa:

Jest z pewnością coś podejrzanego Jeżeli posiłki pliku 700 KB do 140 MB pamięci z tym kodem, który podałeś (możesz mieć relację unset $ na końcu każdej iteracji). Rozważ skorzystanie z debuggera, aby sprawdzić, co się stanie. Można też rozważyć przepisanie kodu użyć SplFileObject's CSV functions jak dobrze (or their procedural cousins)

SplFileObject::setCsvControl example

$file = new SplFileObject("data.csv"); 
$file->setFlags(SplFileObject::READ_CSV); 
$file->setCsvControl('|'); 
foreach ($file as $row) { 
    list ($fruit, $quantity) = $row; 
    // Do something with values 
} 

na podejście OOP iteracyjne nad pliku, spróbuj SplFileObject:

SplFileObject::fgets example

$file = new SplFileObject("file.txt"); 
while (!$file->eof()) { 
    echo $file->fgets(); 
} 

SplFileObject::next example

// Read through file line by line 
$file = new SplFileObject("misc.txt"); 
while (!$file->eof()) { 
    echo $file->current(); 
    $file->next(); 
} 

lub nawet

foreach(new SplFileObject("misc.txt") as $line) { 
    echo $line; 
} 

Prawie podobne (jeśli nie powielać):

+0

Myślę, że to nadal może potencjalnie wykorzystać dużą porcję pamięci, ponieważ myślę, że nadal czyta, dopóki nie znajdzie końca linii. – Artefacto

+0

tak samo jak powyżej, chcę czytać wiersz po wierszu (zakończone przez \ n) – Chetan

+0

@Artefakto cóż, nadal możesz użyć 'SplFileObject :: setMaxLineLen', jeśli jest to problem. – Gordon

0

przydzielić więcej pamięci podczas pracy, może coś jak w i_set ('memory_limit', '16M') ;. Nie zapomnij wrócić do początkowej alokacji pamięci po wykonaniu operacji

+0

Jestem prawie pewien, że nie musisz resetować limitu pamięci po operacji, dotyczy to tylko aktualnie uruchomionego skryptu. –

+0

Używam już 140 MB pamięci (z czytania tego pliku dzieje się dużo rzeczy) – Chetan

+1

@Chetan to brzmi dla mnie podejrzanie. 50k linii za dużo. [Biblia Króla Jakuba] (http://www.gutenberg.org/etext/26361) ma około 20k linii, jest 1MB w postaci zwykłego tekstu i zajmuje tylko około 3 MB podczas odczytu z pliku(). Jaki jest całkowity rozmiar w bajtach twojego pliku? – Gordon

1

Jeśli nie znasz maksymalnej długości linii i nie jesteś w stanie użyć magicznej liczby dla maksymalnej długości linii, musisz wykonaj wstępne skanowanie pliku i określ maksymalną długość linii.

Poza tym, że następujący kod powinien pomóc:

// length is a large number or calculated from an initial file scan 
    while (!feof($handle)) { 
     $buffer = fgets($handle, $length); 
     echo $buffer; 
    }