Obtener el tamaño sin comprimir de un archivo .gz en Python

Usando gzip, tell () devuelve el desplazamiento en el archivo sin comprimir.
Para mostrar una barra de progreso, quiero saber el tamaño original (sin comprimir) del archivo.
¿Hay una manera fácil de averiguarlo?

El formato gzip especifica un campo llamado ISIZE que:

Esto contiene el tamaño de los datos de entrada originales (sin comprimir) módulo 2 ^ 32.

En gzip.py , que asumo que es lo que estás usando para el soporte de gzip, hay un método llamado _read_eof definido como tal:

 def _read_eof(self): # We've read to the end of the file, so we have to rewind in order # to reread the 8 bytes containing the CRC and the file size. # We check the that the computed CRC and size of the # uncompressed data matches the stored values. Note that the size # stored is the true file size mod 2**32. self.fileobj.seek(-8, 1) crc32 = read32(self.fileobj) isize = U32(read32(self.fileobj)) # may exceed 2GB if U32(crc32) != U32(self.crc): raise IOError, "CRC check failed" elif isize != LOWU32(self.size): raise IOError, "Incorrect length of data produced" 

Allí puede ver que se está leyendo el campo ISIZE , pero solo para compararlo con self.size para la detección de errores. Esto debería significar que GzipFile.size almacena el tamaño real sin comprimir. Sin embargo, creo que no está expuesto públicamente, por lo que es posible que tenga que piratearlo para exponerlo. No estoy tan seguro, lo siento.

Acabo de ver todo esto ahora mismo, y no lo he probado por lo que podría estar equivocado. Espero que esto te sea de alguna utilidad. Lo siento si malinterpreté tu pregunta.

El tamaño sin comprimir se almacena en los últimos 4 bytes del archivo gzip. Podemos leer los datos binarios y convertirlos en un int. (Esto solo funcionará para archivos de menos de 4GB)

 import struct def getuncompressedsize(filename): with open(filename, 'rb') as f: f.seek(-4, 2) return struct.unpack('I', f.read(4))[0] 

Modo Unix: use “gunzip -l file.gz” a través de subprocess.call / os.popen, capture y analice su salida.

Los últimos 4 bytes de .gz contienen el tamaño original del archivo

  f = gzip.open(filename) # kludge - report uncompressed file position so progess bars # don't go to 400% f.tell = f.fileobj.tell 

No estoy seguro del rendimiento, pero esto podría lograrse sin conocer gzip magic utilizando:

 with gzip.open(filepath, 'rb') as file_obj: file_size = file_obj.seek(0, io.SEEK_END) 

Esto también debería funcionar para otros lectores de flujo (comprimidos) como bz2 o el plano open .

EDITAR: como se sugiere en los comentarios, 2 en la segunda línea fue reemplazado por io.SEEK_END , que es definitivamente más legible y probablemente más a prueba de futuro.

EDITAR: Funciona solo en Python 3.

A pesar de lo que dicen las otras respuestas, los últimos cuatro bytes no son una forma confiable de obtener la longitud sin comprimir de un archivo gzip. Primero, puede haber varios miembros en el archivo gzip, de modo que solo sería la longitud del último miembro. En segundo lugar, la longitud puede ser más de 4 GB, en cuyo caso los últimos cuatro bytes representan la longitud módulo 2 32 . No es la longitud.

Sin embargo, para lo que desee, no es necesario obtener la longitud sin comprimir. En su lugar, puede basar su barra de progreso en la cantidad de entrada consumida, en comparación con la longitud del archivo gzip, que se obtiene fácilmente. Para datos homogéneos típicos, esa barra de progreso mostraría exactamente lo mismo que una barra de progreso basada en los datos sin comprimir.

En cuanto a la fuente del módulo gzip , veo que el objeto de archivo subyacente para GzipFile parece ser fileobj . Asi que:

 mygzipfile = gzip.GzipFile() ... mygzipfile.fileobj.tell() 

?

Tal vez sería bueno hacer una comprobación de cordura antes de hacerlo, como verificar que el atributo existe con hasattr .

No es exactamente una API pública, pero …

GzipFile.size almacena el tamaño sin comprimir, pero solo se incrementa al leer el archivo, por lo que debería preferir len (fd.read ()) en lugar del no público GzipFile.size.

 import gzip File = gzip.open("input.gz", "r") Size = gzip.read32(File)