Python中的Tarfile:我可以通过仅提取一些数据来更有效地解压吗?

时间:2014-09-26 20:03:38

标签: python performance tarfile

我正在订购美国地质勘探局的巨大土地场景,这些场景来自tar.gz档案。我正在编写一个简单的python脚本来解压缩它们。每个存档包含15个60-120 mb的tiff图像,总计超过2 gb。我可以使用以下代码轻松提取整个存档:

import tarfile
fileName = "LT50250232011160-SC20140922132408.tar.gz"
tfile = tarfile.open(fileName, 'r:gz')
tfile.extractall("newfolder/")

我实际上只需要15个tiff中的6个,标题中标识为“band”。这些是一些较大的文件,因此它们共同占据了大约一半的数据。所以,我认为我可以通过修改代码来加快这个过程:

fileName = "LT50250232011160-SC20140922132408.tar.gz"
tfile = tarfile.open(fileName, 'r:gz')
membersList = tfile.getmembers()
namesList = tfile.getnames()
bandsList = [x for x, y in zip(membersList, namesList) if "band" in y]
print("extracting...")
tfile.extractall("newfolder/",members=bandsList)

然而,在两个脚本中添加一个计时器显示第二个脚本没有明显的效率提升(在我的系统上,两个脚本在一个场景上运行大约一分钟)。虽然提取速度稍微快一点,但似乎这个增益可以通过确定首先需要提取哪些文件所花费的时间来抵消。

问题是,这种权衡取决于我正在做什么,或者仅仅是我的代码效率低下的结果?我是python的新手,今天才发现tarfile,所以如果后者是真的我也不会感到惊讶,但是我还没有找到任何有效提取档案的部分建议。

谢谢!

2 个答案:

答案 0 :(得分:6)

您可以通过将tar文件作为流打开来更有效地执行此操作。(https://docs.python.org/2/library/tarfile.html#tarfile.open

mkdir tartest
cd tartest/
dd if=/dev/urandom of=file1 count=100 bs=1M
dd if=/dev/urandom of=file2 count=100 bs=1M
dd if=/dev/urandom of=file3 count=100 bs=1M
dd if=/dev/urandom of=file4 count=100 bs=1M
dd if=/dev/urandom of=file5 count=100 bs=1M
cd ..
tar czvf test.tgz tartest

现在读完如下:

import tarfile
fileName = "test.tgz"
tfile = tarfile.open(fileName, 'r|gz')
for t in tfile:
    if "file3" in t.name: 
        f = tfile.extractfile(t)
        if f:
            print(len(f.read()))

请注意open命令中的|。我们只阅读了file3

$ time python test.py

104857600

real    0m1.201s
user    0m0.820s
sys     0m0.377s

如果我将r|gz更改回r:gz我得到:

$ time python test.py 
104857600

real    0m7.033s
user    0m6.293s
sys     0m0.730s

大约快5倍(因为我们有5个大小相同的文件)。这是因为标准的开放方式允许向后寻求;它只能通过提取在压缩的tarfile中这样做(我不知道确切的原因)。如果您以流形式打开,则无法再随机查找,但如果您按顺序阅读,这在您的情况下可能会更快。但是,您不能事先到getnames。但在这种情况下,这不是必要的。

答案 1 :(得分:4)

问题是tar文件没有中央文件列表,但在每个文件之前按a header顺序存储文件。然后通过gzip压缩tar文件,为您提供tar.gz。使用tar文件,如果您不想提取某个文件,只需跳过存档中的下一个header->size字节,然后读取下一个标题。如果存档被另外压缩,您仍然必须跳过那么多字节,只是不在存档文件中,而是在解压缩的数据流中 - for some compression formats works, but for others requires you to decompress everything in between

gzip属于后一类压缩方案。因此,虽然通过不将不需要的文件写入磁盘节省了一些时间,但您的代码仍会解压缩它们。您可以通过覆盖非{gzip档案的_Stream class来克服该问题,但对于您的gz文件,您无能为力。