【问题标题】:Reading lines from gzipped text file in Python and get number of original compressed bytes read从 Python 中的压缩文本文件中读取行并获取读取的原始压缩字节数
【发布时间】:2018-02-13 11:19:13
【问题描述】:

我有许多 gzip 压缩的文本文件,我想在运行中(在线)解压缩和读取并进行处理,这样我就可以节省磁盘空间,还可以节省从磁盘读取数据的时间,但会牺牲在线解压缩的时间。

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

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

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

我怎样才能做到这一点?

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

我正在使用 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)

【问题讨论】:

    标签: python gzip filesize


    【解决方案1】:

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

    如果您正在遍历文件,使用tell() 的光标位置将是从磁盘读取的字节数。

    请参阅textIO wrapper doc 了解buffer 的用法和gzip doc 了解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
    

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

    with open('filename.gz', 'rb') as f, gzip.open(f, 'rt') as file:
        for line in file:
            pbar.n = f.tell()  # Another way to set progress when we know total progress rather than increment
            pbar.update(0)   # Call refresh if needed
            # Do things
    

    【讨论】:

      【解决方案2】:

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

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

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

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

      【讨论】:

        【解决方案3】:

        你的问题有答案。不要跟踪未压缩字节的进度。跟踪压缩字节的进度。对于自洽的压缩文件,它们大致彼此成比例,因此您将获得相同的效果。很容易找到压缩文件的大小。

        【讨论】:

          【解决方案4】:

          这是我所做的:

          import gzip
          import tqdm
          import os
          
          
          def _reader_generator(reader):
              b = reader(1024 * 1024)
              while b:
                  yield b
                  b = reader(1024 * 1024)
          
          def raw_newline_count_gzip(fname):
              f = gzip.open(fname, 'rb')
              f_gen = _reader_generator(f.read)
              return sum(buf.count(b'\n') for buf in f_gen)
          
          num = raw_newline_count_gzip('filename.gz')
          
          with gzip.open('filename.gz', 'rt') as file:
              with tqdm(total=num) as pbar:
                  for line in file:
                      bytes_uncompressed = len(line.encode('utf-8'))
                      # do whatever you want
          
                      pbar.update(1)
          
          

          希望这适用于您的文件。

          【讨论】:

            猜你喜欢
            • 2012-05-20
            • 1970-01-01
            • 2013-10-15
            • 1970-01-01
            • 1970-01-01
            • 2015-01-12
            • 1970-01-01
            • 2023-01-26
            • 1970-01-01
            相关资源
            最近更新 更多