我有许多gzip压缩文本文件,我想在运行中解压缩并在线阅读和处理,这样我就可以节省磁盘空间,还可以节省从磁盘读取数据的时间,但代价是在线解压缩。
所以我使用gzip模块和tqdm来跟踪进度。
但是如何确定原始未压缩文件大小的大小,以便设置在完成之前读取的总字节数(未压缩)计数以跟踪进度?据我所知,在搜索网页时,gzip对于大于4千兆字节的文件很难解决这个问题。
或者我应该跟踪读取的压缩字节数,使用压缩文件的大小设置总字节数。
我怎样才能实现?
以下是代码示例,其中的注释也反映了我想要实现的目标。
我使用的是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)
答案 0 :(得分:4)
您应该打开以读取基础文件(以二进制模式)f = open('filename.gz', 'rb')
。然后打开gzip文件。 g = gzip.GzipFile(fileobj=f)
。您从g
执行读取操作,并告诉您有多远,您{cat f.tell()
在压缩文件中询问位置。
EDIT2:BTW。当然,您也可以使用tell()
实例上的GzipFile
告诉您未解压缩的文件有多远(读取字节数)。
编辑:现在我看到这只是你问题的部分答案。你也需要总数。在那里,我担心你有点不走运。 ESP。对于超过4GB的文件,您已经注意到了。 gzip在最后四个字节中保持未压缩的大小,因此你可以跳转并读取它们并跳回(GzipFile
似乎不会公开这些信息),但由于它是四个字节,你只能存储4GB作为最大数字,其余只是被截断到值的较低4B。在那种情况下,我恐怕你不会知道,直到最后。
无论如何,上面的提示会给你当前压缩和未压缩的位置,希望你能够至少在某种程度上达到你想要做的目的。
答案 1 :(得分:2)
你的问题有答案。不跟踪未压缩字节的进度。跟踪压缩字节的进度。对于自洽的压缩文件,它们大致相互成比例,因此您将获得相同的效果。很容易找到压缩文件的大小。
答案 2 :(得分:0)
这是我所做的:
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)
希望这对您的文件有效。
答案 3 :(得分:0)
尝试自己实现此目的后,我找到了简单的解决方案(文档中并未明确说明)。当以文本形式打开时,您可以使用gzippedfile.buffer.fileobj
访问基础文件对象,而对于二进制文件则可以使用gzippedfile.fileobj
访问二进制文件,然后可以使用它们来获取光标的位置(读取的压缩字节数,如果通过该文件),方法是调用tell()
。
有关buffer
的用法,请参见textIO wrapper doc,有关fileobj
的{{3}}请参见
对于您而言,您可以执行以下操作:
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