从 Python 中的 gzip 压缩文本文件中读取行并获取读取的原始压缩字节数

kon*_*unn 3 python gzip filesize

我有许多 gzip 压缩的文本文件,我想解压缩并即时(在线)读取和处理,这样我就可以节省磁盘空间和从磁盘读取数据的时间,但代价是在线解压缩的时间。

所以我使用 gzip 模块和 tqdm 来跟踪进度。

但是,如何找出原始未压缩文件大小的大小,以便在完成跟踪进度之前设置要读取的总字节数(未压缩)计数?就我在网上搜索而言,对于大于 4 GB 的文件,这个问题很难在 gzip 中解决,这就是我的情况。

或者,我应该跟踪读取的压缩字节数,将总字节数设置为压缩文件的大小。

我怎样才能做到这一点?

这是下面的代码示例,其中的注释也反映了我想要实现的目标。

我正在使用 Python 3.5 。

import gzip
import tqdm
import os

size = os.path.getsize('filename.gz')
pbar = tqdm.tqdm(total=size, unit='b', unit_scale=True, unit_divisor=1024)

with gzip.open('filename.gz', 'rt') as file:
    for line in file:
        bytes_uncompressed = len(line.encode('utf-8'))
        # but how can I get compressed bytes read count?
        # bytes_compressed = ...?

        # pbar.update(bytes_compressed)
Run Code Online (Sandbox Code Playgroud)

Ond*_* K. 5

您应该打开以读取底层文件(以二进制模式)f = open('filename.gz', 'rb')。然后在其上打开 gzip 文件。g = gzip.GzipFile(fileobj=f). 你从 执行你的读操作g,并告诉你有多远,你 catf.tell()要求在压缩文件中的位置。

EDIT2:顺便说一句。当然,您也可以tell()GzipFile实例上使用来查看您的未压缩文件的距离(读取的字节数)。

编辑:现在我看到这只是您问题的部分答案。你还需要总数。恐怕你有点不走运。特别是 如您所见,对于超过 4GB 的文件。gzip 将未压缩的大小保留在最后四个字节中,因此您可以跳到那里并读取它们并跳回(GzipFile似乎并没有公开此信息本身),但是由于它是四个字节,因此您只能存储 4GB 作为最大数字,休息一下被截断到值的较低 4B。那样的话,恐怕直到最后你也不会知道。

无论如何,以上提示为您提供了压缩和未压缩的当前位置,希望这能让您至少在某种程度上实现您的目标。


Das*_*ash 5

在尝试自己实现这个之后,我找到了简单的解决方案(文档中没有明确说明)。gzippedfile.buffer.fileobj当作为文本文件打开时以及gzippedfile.fileobj作为二进制文件打开时,您可以访问底层文件对象。

如果您要迭代文件,则使用的光标位置tell()将是从磁盘读取的字节数。

有关用法,请参阅textIO 包装器文档;有关buffer使用方法,请参阅gzip 文档。fileobj

对于你的情况,你可以这样做:

with open('filename.gz', 'rt') as file:
    for line in file:
        pbar.update(file.buffer.fileobj.tell() - pbar.n)   # tqdm uses incremental update, so 
                                                   # increment is (current - last value)
        # Do things
Run Code Online (Sandbox Code Playgroud)

如果您确实需要访问二进制文件,这里是 @Mark Adler 建议的示例实现

with open('filename.gz', 'rt') as file:
    for line in file:
        pbar.update(file.buffer.fileobj.tell() - pbar.n)   # tqdm uses incremental update, so 
                                                   # increment is (current - last value)
        # Do things
Run Code Online (Sandbox Code Playgroud)