在Python中获取.gz文件的未压缩大小

17 投票
11 回答
18763 浏览
提问于 2025-04-15 15:50

使用gzip时,tell()这个函数会返回未压缩文件的偏移量。
为了显示进度条,我想知道文件的原始(未压缩的)大小。
有没有简单的方法可以找到这个信息呢?

11 个回答

14

尽管其他回答可能这么说,但最后四个字节并不是获取gzip文件未压缩长度的可靠方法。首先,gzip文件里可能有多个部分,所以这四个字节只代表最后一个部分的长度。其次,如果长度超过4GB,这最后四个字节实际上是长度对232取模的结果,而不是实际长度。

不过,对于你想要的情况,其实不需要获取未压缩的长度。你可以根据已处理的输入量来显示进度条,这个输入量和gzip文件的总长度相比是很容易获取的。对于典型的同质数据,这个进度条显示的内容和基于未压缩数据的进度条是完全一样的。

24

未压缩的文件大小存储在gzip文件的最后4个字节中。我们可以读取这些二进制数据,并把它转换成一个整数。(这个方法只适用于小于4GB的文件)

import struct

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

gzip格式中有一个叫做 ISIZE 的字段:

这个字段包含了原始(未压缩)输入数据的大小,计算方式是对2的32次方取余。

gzip.py文件中,我猜这就是你用来支持gzip的代码,有一个叫 _read_eof 的方法,定义如下:

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"

在这里你可以看到 ISIZE 字段被读取,但只是为了和 self.size 进行比较,以检测错误。这意味着 GzipFile.size 存储的是实际的未压缩大小。不过,我 觉得 这个信息并没有公开,所以你可能需要自己动手去修改代码才能看到它。对此我不是很确定,抱歉。

我刚刚查了这些信息,实际上我还没有尝试过,所以可能会有错误。希望这些对你有帮助。如果我误解了你的问题,抱歉。

撰写回答