Méthode la plus rapide pour calculer la taille non compressée d'un gros fichier GZIPPED

24

Une fois un fichier compressé, y a-t-il un moyen de l'interroger rapidement pour dire quelle est la taille du fichier non compressé (sans le décompresser), en particulier dans les cas où le fichier non compressé a une taille> 4 Go.

Selon la RFC https://tools.ietf.org/html/rfc1952#page-5, vous pouvez interroger les 4 derniers octets du fichier, mais si le fichier non compressé était> 4 Go, la valeur représente simplement leuncompressed value modulo 2^32

Cette valeur peut également être récupérée en exécutant gunzip -l foo.gz, mais la colonne "non compressée" contient juste à uncompressed value modulo 2^32nouveau, probablement pendant la lecture du pied de page comme décrit ci-dessus.

Je me demandais simplement s'il y avait un moyen d'obtenir la taille du fichier non compressé sans avoir à le décompresser au préalable, cela serait particulièrement utile dans le cas où les fichiers compressés contiennent plus de 50 Go de données et prendraient un certain temps pour décompresser en utilisant des méthodes comme gzcat foo.gz | wc -c


EDIT: La limitation de 4 Go est ouvertement reconnue dans la manpage de l' gziputilitaire inclus avec OSX ( Apple gzip 242)

  BUGS
    According to RFC 1952, the recorded file size is stored in a 32-bit
    integer, therefore, it can not represent files larger than 4GB. This
    limitation also applies to -l option of gzip utility.
djhworld
la source
2
+1 bonne question! Je soupçonne que la réponse est non, que le format d'en-tête a été conçu à une époque antérieure à la prévision de telles tailles de fichier. En y réfléchissant, il gzipdoit être plus âgé que de nombreux utilisateurs de cette communauté!
Celada
2
gzipest sorti en 1992. Je serais surpris s'il y avait beaucoup de jeunes de 23 ans qui errent ici. Je suis sûr qu'il y en a mais d'après ce que je peux dire, l'âge médian se situe autour de 30-35 ans.
Bratchley
2
Peut être un bon moment pour passer à celui xzqui n'a pas cette limitation. GNU passe à xz.
Stéphane Chazelas
@ StéphaneChazelas Intéressant. Malheureusement, les fichiers qui m'intéressent sont hors de mon contrôle (c'est-à-dire que nous les recevons compressés), mais il semblerait que xz cela «résoudrait» ce problème.
djhworld

Réponses:

11

Je crois que le moyen le plus rapide est de modifier de gzipsorte que les tests en mode verbeux produisent le nombre d'octets décompressés; sur mon système, avec un fichier de 7761108684 octets, j'obtiens

% time gzip -tv test.gz
test.gz:     OK (7761108684 bytes)
gzip -tv test.gz  44.19s user 0.79s system 100% cpu 44.919 total

% time zcat test.gz| wc -c
7761108684
zcat test.gz  45.51s user 1.54s system 100% cpu 46.987 total
wc -c  0.09s user 1.46s system 3% cpu 46.987 total

Pour modifier gzip (1.6, comme disponible dans Debian), le patch est le suivant:

--- a/gzip.c
+++ b/gzip.c
@@ -61,6 +61,7 @@
 #include <stdbool.h>
 #include <sys/stat.h>
 #include <errno.h>
+#include <inttypes.h>

 #include "closein.h"
 #include "tailor.h"
@@ -694,7 +695,7 @@

     if (verbose) {
         if (test) {
-            fprintf(stderr, " OK\n");
+            fprintf(stderr, " OK (%jd bytes)\n", (intmax_t) bytes_out);

         } else if (!decompress) {
             display_ratio(bytes_in-(bytes_out-header_bytes), bytes_in, stderr);
@@ -901,7 +902,7 @@
     /* Display statistics */
     if(verbose) {
         if (test) {
-            fprintf(stderr, " OK");
+            fprintf(stderr, " OK (%jd bytes)", (intmax_t) bytes_out);
         } else if (decompress) {
             display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out,stderr);
         } else {
Stephen Kitt
la source
Construit-il toujours les données réelles en interne ou est-il -tdéjà optimisé à cet égard? L'amélioration est suffisamment petite pour donner l'impression que vous n'avez enregistré que le temps de sortie.
frostschutz
Oui, il faut tout décompresser pour déterminer la taille d'origine ... Donc, cela ne fait que gagner du temps en sortie, mais je pense que c'est tout ce qui peut être enregistré.
Stephen Kitt
Intéressant, oui, je pensais que vous auriez besoin de changer le code pour que cela fonctionne. Malheureusement, dans mon cas, les fichiers qui m'intéressent ne sont pas réellement sous mon contrôle, je les reçois d'une partie externe, donc je ne serais pas en mesure de les compresser en premier lieu. Je pense que la seule façon de supporter pleinement les fichiers> 4 Go serait de patcher gzip pour avoir un pied de page de 12 octets, 4 octets pour CRC et 8 octets (64 bits) pour la taille du fichier. Cependant, cela romprait la compatibilité avec les gzips existants!
djhworld
La solution que je donne ci-dessus n'implique pas de compresser les fichiers au départ, même si je suis en cours d'exécution gzip; Je viens de courir gzipsur les fichiers compressés, ce qui ne les recompresse pas, il les vérifie. (Le patch est une preuve de concept rapide et sale, il a besoin de quelques modifications supplémentaires pour fonctionner gunzip.)
Stephen Kitt
@StephenKitt Ah intéressant! Un hack encore meilleur / plus sale serait d'intégrer ces données sur le FCOMMENTterrain. De cette façon, les utilisateurs peuvent interroger une plage d'octets pour récupérer ces données. Cela serait utile dans mon cas, en particulier pour les articles stockés dans Amazon S3
djhworld
0

Si vous avez besoin de la taille d'un fichier compressé ou un ensemble de fichiers, votre meilleur pari est d'utiliser tar -zou au tar -jlieu de gzipque tarcomprend la taille des fichiers non compressés. Utilisez lesspipepour jeter un œil à la liste des fichiers:

aptitude install lesspipe
lesspipe <compressed file> | less

Si lessest configuré pour utiliser lesspipe:

less <compressed file>

N'oubliez pas que cela peut prendre très longtemps. Cependant, votre système reste réactif, ce qui vous permet de tuer le processus de décompression.

Une autre approche consisterait à enregistrer le rapport compressé et à interroger ce fichier [texte] à la place:

gzip --verbose file 2>&1 | tee file.gz.log
file:    64.5% -- replaced with file.gz

Il nécessite cependant des calculs pour trouver la taille réelle du fichier.

Vous pouvez également faire de même avec tar, ce qui est en fait ce que je fais avec les sauvegardes de grande taille car cela empêche d'exécuter tout le processus de décompression pour obtenir uniquement une taille de fichier ou un nom, par exemple.


la source
2
Tar.gz ne doit-il pas également être décompressé complètement pour obtenir la liste de tous les fichiers?
frostschutz
En effet, il doit en être ainsi. C'est le seul moyen auquel je peux penser pour obtenir la taille du fichier non compressé. Avec tarvous avez la taille du fichier d'origine enregistré dans l'archive. D'un autre côté, je ne suis pas sûr de zipse comporter différemment.
1
À ce stade, l'OP pourrait tout aussi bien exécuter la wc -ccommande.
Bratchley
@Bratchley bien sûr. Mais il faudrait un temps considérable pour obtenir tous les résultats. D'où mes deux suggestions pour enregistrer la taille des fichiers.
0

Qu'en est-il de

gzip -l file.gz|tail -n1|awk '{print $2}'

numfmt --to=iec $(gzip -l file.gz|tail -n1|awk '{print $2}')
Syco
la source
1
Cela ne fonctionne pas pour les gros fichiers, comme l'explique l'OP.
Stephen Kitt
-2
gunzip -c $file | wc -c

Cela prendra beaucoup de temps, mais vous donnera la taille finale en octets.

Entaille
la source
5
C'est exactement ce que l'OP essaie d'éviter d'avoir à faire.
depquid