Scompatta file di grandi dimensioni con gzip in PHP
Domanda
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.
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 es. 50mb) per decomprimere richiede una grande quantità di ram per l'elaborazione.
La domanda: posso 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 ci vogliono alcuni secondi in più)?
Soluzione
gzfile () è un metodo pratico che chiama gzopen, gzread e gzclose.
Quindi, sì, puoi eseguire manualmente gzopen e gzread il file in blocchi.
Questo decomprimerà il file in blocchi da 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);
}
Altri suggerimenti
prova con
function uncompress($srcName, $dstName) {
$fp = fopen($dstName, "w");
fwrite($fp, implode("", gzfile($srcName)));
fclose($fp);
}
Il parametro $ length è facoltativo.
Se sei su un host Linux, hai i privilegi necessari per eseguire i comandi e il comando gzip è installato, potresti provare a chiamarlo con qualcosa come shell_exec
Un po 'come questo, immagino, farebbe:
shell_exec('gzip -d your_file.gz');
In questo modo, il file non verrà decompresso da PHP.
Come sidenote:
- Fai attenzione da dove viene eseguito il comando (o usa uno swith per dire " decomprimere a quella directory ")
- Potresti dare un'occhiata a
escapeshellarg
too ;-)
Come maliayas menzionato, può portare a un bug. Ho riscontrato un inaspettato calo del ciclo while, ma il file gz è stato decompresso correttamente. L'intero codice appare così 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;
}