La forma más rápida de calcular el tamaño sin comprimir de un archivo GZIPPED grande


24

Una vez que se comprime un archivo, ¿hay alguna forma de consultarlo rápidamente para decir cuál es el tamaño del archivo sin comprimir (sin descomprimirlo), especialmente en los casos en que el archivo sin comprimir tiene un tamaño> 4 GB.

De acuerdo con la RFC https://tools.ietf.org/html/rfc1952#page-5 , puede consultar los últimos 4 bytes del archivo, pero si el archivo sin comprimir era> 4 GB, entonces el valor solo representa eluncompressed value modulo 2^32

Este valor también se puede recuperar ejecutando gunzip -l foo.gz, sin embargo, la columna "sin comprimir" solo contiene uncompressed value modulo 2^32nuevamente, presumiblemente porque está leyendo el pie de página como se describe anteriormente.

Me preguntaba si hay una manera de obtener el tamaño del archivo sin comprimir sin tener que descomprimirlo primero, esto sería especialmente útil en el caso de que los archivos comprimidos contengan más de 50 GB de datos y tomaría un tiempo descomprimirlos usando métodos como gzcat foo.gz | wc -c


EDITAR: la limitación de 4 GB se reconoce abiertamente en la manpágina de la gziputilidad incluida con 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.

2
+1 buena pregunta! Sospecho que la respuesta es no, ese formato de encabezado se diseñó antes de que se anticiparan dichos tamaños de archivo. Pensando en ello, ¡ gzipdebe ser mayor que muchos usuarios en esta comunidad!
Celada

2
gzipsalió en 1992. Me sorprendería si hubiera muchos jóvenes de 23 años deambulando por aquí. Estoy seguro de que hay algunos, pero por lo que puedo decir, la edad promedio es de alrededor de 30-35.
Bratchley

2
Puede ser un buen momento para cambiar al xzque no tiene esa limitación. GNU está cambiando a xz.
Stéphane Chazelas

@ StéphaneChazelas Interesante. Lamentablemente, los archivos que me interesan están fuera de mi control (es decir, los recibimos comprimidos), pero ciertamente parece xz que 'resolvería' este problema.
djhworld

Respuestas:


11

Creo que la forma más rápida es modificar gzippara que las pruebas en modo detallado generen la cantidad de bytes descomprimidos; en mi sistema, con un archivo de 7761108684 bytes, obtengo

% 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

Para modificar gzip (1.6, como está disponible en Debian), el parche es el siguiente:

--- 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 {

¿Sigue construyendo los datos reales internamente o -tya está optimizado en ese sentido? La mejora es lo suficientemente pequeña como para que parezca que solo ha guardado el tiempo de salida.
frostschutz

Sí, necesita descomprimir todo para determinar el tamaño original ... Así que esto solo ahorra el tiempo de salida, pero creo que eso es todo lo que se puede guardar.
Stephen Kitt

Interesante, sí, estaba pensando que necesitarías cambiar el código para que esto realmente funcione. Desafortunadamente, en mi caso, los archivos que me interesan no están realmente bajo mi control, los recibo de una parte externa, por lo que no podría comprimirlos en primer lugar. Creo que la única forma de admitir completamente archivos> 4GB sería parchear gzip para tener un pie de página de 12 bytes, 4 bytes para CRC y 8 ​​bytes (64 bits) para el tamaño del archivo. Sin embargo, esto rompería la compatibilidad con gzips existentes.
djhworld

La solución que doy arriba no implica la compresión de los archivos inicialmente, aunque estoy corriendo gzip; Simplemente ejecuto gziplos archivos comprimidos, lo que no los vuelve a comprimir, solo los verifica. (El parche es una prueba de concepto rápida y sucia, necesita algunos cambios más para funcionar gunzip)
Stephen Kitt,

@StephenKitt ¡Ah, interesante! Un truco aún mejor / más sucio sería incrustar esos datos en el FCOMMENTcampo. De esa forma, los usuarios podrían consultar un rango de bytes para recuperar esos datos. Esto sería útil en mi caso, especialmente para los artículos almacenados en Amazon S3
djhworld

0

Si necesita el tamaño de un archivo comprimido o conjunto de archivos, lo mejor es usar tar -zo tar -jen lugar de gzipque tarincluye el tamaño de los archivos sin comprimir. Use lesspipepara echar un vistazo a la lista de archivos:

aptitude install lesspipe
lesspipe <compressed file> | less

Si lessestá configurado para usar lesspipe:

less <compressed file>

Sin embargo, tenga en cuenta que puede llevar mucho tiempo. Sin embargo, su sistema sigue respondiendo, lo que le permite matar el proceso de descompresión.

Otro enfoque sería registrar la relación comprimida y consultar ese archivo [texto] en su lugar:

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

Sin embargo, requiere un cálculo para encontrar el tamaño real del archivo.

También podría hacer lo mismo tar, que de hecho es lo que hago con las copias de seguridad de gran tamaño, ya que impide ejecutar todo el proceso de descompresión para obtener solo un tamaño o nombre de archivo, por ejemplo.


2
¿Tar.gz no tiene que descomprimirse completamente para obtener la lista de todos los archivos?
frostschutz

De hecho tiene que ser. Esta es la única forma en que puedo pensar para obtener el tamaño del archivo sin comprimir. Con tarusted tiene el tamaño del archivo original registrado en el archivo. No estoy seguro de zipcomportarse de manera diferente, por otro lado.

1
En ese punto, el OP también podría hacer el wc -ccomando.
Bratchley

@Bratchley, por supuesto. Pero tomaría una cantidad considerable de tiempo obtener todos los resultados. De ahí mis dos sugerencias para registrar los tamaños de los archivos.

0

Qué pasa

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

numfmt --to=iec $(gzip -l file.gz|tail -n1|awk '{print $2}')

1
Eso no funciona para archivos grandes, como lo explica el OP.
Stephen Kitt

-2
gunzip -c $file | wc -c

Esto llevará mucho tiempo, pero le dará el tamaño final en bytes.


55
Esto es exactamente lo que el OP está tratando de evitar tener que hacer.
depquid
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.