8

我从 USGS 订购了一大堆陆地卫星场景,它们以 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 个,在标题中标识为“乐队”。这些是一些较大的文件,因此它们加起来约占数据的一半。所以,我想我可以通过如下修改代码来加快这个过程:

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,所以如果后者是真的,我不会感到惊讶,但我还没有找到任何有效提取档案的一部分的建议。

谢谢!

4

2 回答 2

9

通过将 tarfile 作为流打开,您可以更有效地做到这一点。(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再事先。但在这种情况下,这不是必需的。

于 2015-09-09T10:18:14.380 回答
8

问题是tar文件没有中央文件列表,而是按顺序存储文件,每个文件之前都有一个标题。然后通过 gzip 压缩该tar文件,为您提供tar.gz. 对于一个tar文件,如果您不想提取某个文件,您只需跳过header->size存档中的下一个字节,然后读取下一个标题。如果存档被额外压缩,您仍然必须跳过那么多字节,不仅不是在存档文件中,而是在解压缩的数据流中 - 这对于某些压缩格式有效,但对于其他压缩格式,您需要解压缩介于两者之间的所有内容

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

于 2014-09-26T20:26:30.683 回答