2009-08-04 12 views
11

Sto usando una semplice funzione di decompressione (come visto sotto) per i miei file, quindi non devo decomprimere i file manualmente prima che vengano elaborati ulteriormente.Scompattiamo file di grandi dimensioni con gzip in PHP

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

Il problema è che se il file gzip è grande (ad esempio 50mb) la decompressione richiede una grande quantità di ram processo.

La domanda: è possibile analizzare un file gzip in blocchi e ottenere comunque il risultato corretto? O c'è un altro modo migliore per gestire il problema dell'estrazione di file gzip di grandi dimensioni (anche se richiede qualche secondo in più)?

risposta

41

gzfile() è un metodo comodo che chiama gzopen, gzread e gzclose.

Quindi, sì, è possibile eseguire manualmente il gzopen e gzread il file in blocchi.

Ciò decomprimere il file in blocchi 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

Dolce! Testato su un file da 1 MB gzip che estrae a 48MB - prima: il tempo di processo: 12.1447s, l'uso della memoria di picco: 96512kB - La tua soluzione: tempo di processo: 0.6705s, l'uso della memoria di picco: 256kB Grazie :) – Lukas

+0

Si può ottenere prestazioni migliori modificando il numero alla fine della chiamata gzread. Non l'ho provato però. – Powerlord

+0

20 volte meglio è abbastanza buono, e rimarrà abbastanza buono per un tempo molto lungo. Dovrei essere molto disperato o usare file enormi per provare a modificare ulteriormente questa cosa :) – Lukas

1

provare con

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

parametro $ lunghezza è facoltativo.

+0

Sembra che questo approccio faccia lo stesso approccio originale utilizzando una grande quantità di memoria. L'intero file viene letto e conservato in memoria. – Lukas

+0

non vengono caricati in un file di dati variabili (simile allo streaming). non è un modello a oggetti in cui caricare la stringa dell'oggetto. Questo esempio non ha effetto su "php_value memory_limit". il tuo esempio influenza questa variabile nel file "php.ini". –

1

Se sono su un host Linux, hanno le privilegies necessarie per eseguire i comandi, e viene installato il comando gzip, si potrebbe provare a chiamare con qualcosa come shell_exec

qualcosa di un po 'come questo, credo, sarebbe do:

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

In questo modo, il file non verrà decompresso da PHP.


Come sidenote:

  • Fare attenzione in cui il comando viene eseguito da (ot utilizzare uno swith per dire "decomprimere, da che directory")
  • Si potrebbe desiderare di dare un'occhiata allo escapeshellarg ;-)
+0

Grazie, ho accesso alla shell, ma devo ancora imparare come usarlo. – Lukas

0

Come maliayas accennato, può portare a un bug. Ho sperimentato un inaspettato abbandono del ciclo while, ma il file gz è stato decompresso correttamente. L'intero codice appare come questo e funziona meglio per me:

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; 
} 
Problemi correlati