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?

16
Paul Oyster 10 nov. 2009 a las 01:43

10 respuestas

La mejor respuesta

El formato gzip especifica un campo llamado ISIZE que :

Contiene el tamaño del módulo de datos de entrada original (sin comprimir) 2 ^ 32.

En gzip.py, que supongo es lo que está utilizando 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 el campo ISIZE se está leyendo, 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 creo no está expuesto públicamente, por lo que es posible que deba piratearlo para exponerlo. No estoy tan seguro, lo siento.

Acabo de mirar todo esto en este momento, y no lo he intentado, así que podría estar equivocado. Espero que esto te sea de utilidad. Lo siento si entendí mal tu pregunta.

16
Jorge Israel Peña 9 nov. 2009 a las 23:18
import gzip

File = gzip.open("input.gz", "r")
Size = gzip.read32(File)
-2
user2165857 10 ene. 2014 a las 17:53

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

0
Guilherme Salgado 17 nov. 2009 a las 17:04

Al mirar la fuente del módulo gzip, veo que el objeto de archivo subyacente para GzipFile parece ser fileobj. Entonces:

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

?

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

No es exactamente una API pública, pero ...

0
Matt Anderson 9 nov. 2009 a las 22:52

32

Sin embargo, para lo que desea, 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 los 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.

6
Mark Adler 25 ene. 2019 a las 07:26
    f = gzip.open(filename)
    # kludge - report uncompressed file position so progess bars
    # don't go to 400%
    f.tell = f.fileobj.tell
1
Noel Burton-Krahn 15 mar. 2011 a las 00:09

No estoy seguro sobre el rendimiento, pero esto podría lograrse sin conocer la magia gzip usando:

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 (comprimido) como bz2 o el simple open.

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

EDITAR: solo funciona en Python 3.

2
norok2 7 ago. 2018 a las 08:35

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

4
John La Rooy 9 nov. 2009 a las 22:57

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

5
yk4ever 9 nov. 2009 a las 22:47

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

import struct

def getuncompressedsize(filename):
    with open(filename, 'rb') as f:
        f.seek(-4, 2)
        return struct.unpack('I', f.read(4))[0]
21
Brice M. Dempsey 19 mar. 2016 a las 04:22