2009-08-04 9 views
11

J'utilise une simple fonction de décompression (comme ci-dessous) pour mes fichiers, donc je n'ai pas besoin de décompresser les fichiers manuellement avant de les traiter.Déballer des fichiers volumineux avec gzip en PHP

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

Le problème est que si le fichier gzip est grande (par exemple 50MB) la décompression prend une grande quantité de mémoire vive à traiter.

La question: puis-je analyser un fichier gzip en morceaux et obtenir le bon résultat? Ou existe-t-il une autre meilleure façon de gérer le problème de l'extraction de gros fichiers gzip (même si cela prend quelques secondes de plus)? paramètre

Répondre

41

gzfile() est une méthode pratique qui appelle gzopen, gzread et gzclose. Donc, oui, vous pouvez faire manuellement le gzopen et gzread le fichier en morceaux.

Cela décompressez le fichier en morceaux 4Ko:

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

Doux! Testé sur un fichier gzip 1Mo qui extrait à 48Mo - avant: le temps du processus: 12.1447s, utilisation de mémoire de pointe: 96512kB - Votre solution: le temps du processus: 0.6705s, utilisation de mémoire de pointe: 256 Ko Merci :) – Lukas

+0

Vous pouvez obtenir de meilleures performances en ajustant le nombre à la fin de l'appel gzread. Je n'ai pas essayé cependant. – Powerlord

+0

20 fois mieux est assez bon, et restera assez bon pendant très longtemps. Je devrais être très désespéré ou en utilisant des fichiers énormes pour essayer et améliorer cette chose :) – Lukas

1

essai avec

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

longueur $ est facultative.

+0

Il semble que cette approche fasse la même chose que l'approche originale en utilisant une grande quantité de mémoire. Le fichier entier est en train d'être lu et conservé en mémoire. – Lukas

+0

ne sont pas chargés dans un fichier de données variables (similaire à la diffusion en continu). n'est pas un modèle objet où charger la chaîne de l'objet. Cet exemple n'affecte pas "php_value memory_limit". votre exemple affecte cette variable dans le fichier "php.ini". –

1

Si vous êtes sur un hôte Linux, ont les privilegies nécessaires pour exécuter les commandes, et la commande gzip est installé, vous pouvez essayer d'appeler avec quelque chose comme shell_exec

QUELQUE CHOSE un peu comme ça, je pense, serait faire:

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

De cette façon, le fichier ne serait pas décompressé par PHP.


En sidenote:

  • Prenez soin où la commande est exécutée à partir de (ot utiliser un swith dire « décomprimer à que répertoire »)
  • Vous voudrez peut-être jeter un oeil à escapeshellarg aussi ;-)
+0

Merci, j'ai un accès shell, mais je n'ai pas encore appris à l'utiliser. – Lukas

0

Comme maliayas mentionné, il peut conduire à un bug. J'ai rencontré une chute inattendue de la boucle while, mais le fichier gz a été décompressé avec succès. Le code entier ressemble à ceci et fonctionne mieux pour moi:

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; 
} 
Questions connexes