如何在Python中确定gzip文件的Content-Length?

4

我有一个大的压缩文件,想知道内容的大小而不需要解压缩它。我尝试了以下方法:

import gzip
import os

with gzip.open(data_file) as f:
          f.seek(0, os.SEEK_END)
          size = f.tell()

但是我遇到了这个错误

ValueError: Seek from end not supported 

我该怎么做呢?

谢谢。


手册上说os.SEEK_END是用于lseek的。这可能是你需要的。 - llrs
1
可能是在Python中获取.gz文件的未压缩大小的重复问题。 - Christian Berendt
1
根据Python 2.x的file文档,@Llopis,os.SEEK_常量确实是与file.seek一起使用的正确选项。此外,os.lseek在这里不起作用,因为gzip文件对象没有底层的POSIX级文件描述符。 - Dan Lenski
3个回答

2

很遗憾,Python 2.x中的gzip模块似乎没有支持任何确定未压缩文件大小的方法。

然而,gzip将未压缩文件大小以小尾端32位无符号整数的形式存储在文件末尾:http://www.abeel.be/content/determine-uncompressed-size-gzip-file

不幸的是,由于gzip格式仅使用32位整数,因此仅适用于文件大小<4gb;请参阅手册

import os
import struct

with open(data_file,"rb") as f:
    f.seek(-4, os.SEEK_END)
    size, = struct.unpack("<I", f.read(4))
    print size

这种方法除了4 GB限制之外还有其他问题。 - Mark Adler
除了不是每种类型的文件都可以“寻找”,还有哪些类型的文件不能进行此操作? - Dan Lenski
1
请查看我的回答,包括另一个答案的链接。 - Mark Adler
问题在于我正在处理大约10GB的归档文件,所以你的技巧在这里行不通。无论如何,还是谢谢你! - Jprog

2
没有办法在不解压的情况下确定gzip文件中未压缩数据的大小,这是原则性问题。你不需要有足够的空间来存储未压缩数据--你可以在进行解压缩时将其丢弃。但你必须全部解压它。
如果你控制gzip文件的源,并且可以确保a) gzip文件中没有串接的成员,b) 未压缩数据长度小于4GB,c) gzip文件末尾没有杂物,则只有在这种情况下,你才能读取gzip文件的最后四个字节,以获取一个小端整数,该整数表示未压缩数据的长度。
更多详情请参见此答案
以下是Python代码,用于读取gzip文件并打印未压缩长度,无需存储或保存未压缩数据。它将内存使用限制为小缓冲区。这需要Python 3.3或更高版本:
#!/usr/local/bin/python3.4
import sys
import zlib
import warnings
f = open(sys.argv[1], "rb")
total = 0
buf = f.read(1024)
while True:             # loop through concatenated gzip streams
    z = zlib.decompressobj(15+16)
    while True:         # loop through one gzip stream
        while True:     # go through all output from one input buffer
            total += len(z.decompress(buf, 4096))
            buf = z.unconsumed_tail
            if buf == b"":
                break
        if z.eof:
            break       # end of a gzip stream found
        buf = f.read(1024)
        if buf == b"":
            warnings.warn("incomplete gzip stream")
            break
    buf = z.unused_data
    z = None
    if buf == b"":
        buf == f.read(1024)
        if buf == b"":
            break
print(total)

谢谢您的回答,但我不确定您的代码是做什么的:它是给出数据文件中元素的数量还是未压缩文件的大小(以字节为单位)?另外,您的代码中哪个函数需要Python3.3?因为我正在运行的机器上没有选择Python版本的选项(可能是2.7)。 - Jprog
未压缩的大小(以字节为单位)。decompressobjeof 方法是在 3.3 版本中添加的,它需要识别何时到达 gzip 流的末尾。 - Mark Adler

-2
总结一下,我需要打开巨大的压缩文件(> 4GB),因此Dan的技术不适用,而且我想要文件的长度(行数),所以Mark Adler的技术也不合适。
最终,我找到了一个解决方案(虽然不是最优化的,但它可以工作!)可以轻松地转换为压缩文件:
size = 0

with gzip.open(data_file) as f:
  for line in f:
    size+= 1
    pass

return size

谢谢大家,这个论坛的人都非常高效!


2
你的问题并没有要求返回行数。实际上,如果你的尝试成功了,它会从 f.tell() 返回字节数而不是行数。 - Mark Adler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接