2009-08-04 10 views
11

Używam prostej funkcji rozpakowywania (jak widać poniżej) dla moich plików, więc nie muszę rozpakowywać plików ręcznie, zanim zostaną one przetworzone dalej.Rozpakowywanie dużych plików za pomocą gzip w PHP

function uncompress($srcName, $dstName) { 
    $string = implode("", gzfile($srcName)); 
    $fp = fopen($dstName, "w"); 
    fwrite($fp, $string, strlen($string)); 
    fclose($fp); 
} 

Problem polega na tym, że jeśli plik gzip jest duży (na przykład 50 MB), rozpakowanie zajmuje dużą ilość pamięci RAM do przetworzenia.

Pytanie: czy można przeanalizować spakowany plik gzip w kawałki i nadal uzyskać prawidłowy wynik? Czy istnieje lepszy inny sposób radzenia sobie z problemem wyodrębniania dużych plików gzip (nawet jeśli potrwa to kilka sekund)?

Odpowiedz

41

gzfile() to wygodna metoda, która wywołuje gzopen, gzread i gzclose.

Tak, możesz ręcznie zrobić gzopen i gzread plik w porcjach.

Będzie to rozpakować plik w kawałki 4KB:

function uncompress($srcName, $dstName) { 
    $sfp = gzopen($srcName, "rb"); 
    $fp = fopen($dstName, "w"); 

    while (!gzeof($sfp)) { 
     $string = gzread($sfp, 4096); 
     fwrite($fp, $string, strlen($string)); 
    } 
    gzclose($sfp); 
    fclose($fp); 
} 
+3

Słodki! Testowane na pliku 1MB gzip że wyciąga do 48MB - przed: czas procesu: 12.1447s maksymalne wykorzystanie pamięci: 96512kB - Twoje rozwiązanie: Czas procesu: 0.6705s, Peak wykorzystanie pamięci: 256kB Dziękuję :) – Lukas

+0

Użytkownik może uzyskać lepszą wydajność, poprawiając numer na końcu wywołania gzread. Jednak tego nie próbowałem. – Powerlord

+0

20 razy lepszy jest wystarczająco dobry i pozostanie wystarczająco dobry przez bardzo długi czas. Musiałbym być bardzo zdesperowany lub używać ogromnych plików, aby spróbować to ulepszyć :) – Lukas

1

spróbuj

function uncompress($srcName, $dstName) { 
    $fp = fopen($dstName, "w"); 
    fwrite($fp, implode("", gzfile($srcName))); 
    fclose($fp); 
} 

$ długość parametr jest opcjonalny.

+0

Wygląda na to, że podejście to jest identyczne z pierwotnym podejściem przy użyciu dużej ilości pamięci. Cały plik jest odczytywany i przechowywany w pamięci. – Lukas

+0

nie są ładowane do pliku danych zmiennych (podobnie jak w przypadku przesyłania strumieniowego). nie jest modelem obiektowym, w którym ładowany jest ciąg obiektowy. Ten przykład nie wpływa na "php_value memory_limit". Twój przykład wpływa na tę zmienną w pliku "php.ini". –

1

Jeśli jesteś na Linuksie, posiadają wymagane privilegies wykonywać polecenia, a zainstalowany jest komenda gzip, można spróbować nazywając ją z czymś shell_exec

coś trochę jak to, jak sądzę, byłoby do:

shell_exec('gzip -d your_file.gz'); 

W ten sposób plik nie zostanie rozpakowany przez PHP.


Jak sidenote:

  • Uważaj gdzie polecenie jest uruchamiane z (ot użyć Swith powiedzieć „rozpakować do że katalog”)
  • Czasami warto spojrzeć pod numerem escapeshellarg ;-)
+0

Dziękuję, mam dostęp do powłoki, ale muszę jeszcze się nauczyć, jak z niej korzystać. – Lukas

0

Jak maliayas wspomniano, może to prowadzić do błędów. Doświadczyłem nieoczekiwanego upadku pętli while, ale plik gz został pomyślnie zdekompresowany. Cały kod wygląda tak i działa lepiej dla mnie:

function gzDecompressFile($srcName, $dstName) { 
    $error = false; 

    if($file = gzopen($srcName, 'rb')) { // open gz file 

     $out_file = fopen($dstName, 'wb'); // open destination file 

     while (($string = gzread($file, 4096)) != '') { // read 4kb at a time 
      if(!fwrite($out_file, $string)) { // check if writing was successful 
       $error = true; 
      } 
     } 

     // close files 
     fclose($out_file); 
     gzclose($file);  

    } else { 
     $error = true; 
    } 

    if ($error) 
     return false; 
    else 
     return true; 
} 
Powiązane problemy