解压缩.gz文件并将其存储在.tar.gz档案中

时间:2019-01-02 15:08:41

标签: python python-3.x gzip tarfile

我遇到以下问题:我正在编写一个函数,该函数查找一堆.gz文件,将其解压缩,并将各个未压缩的文件存储在更大的.tar.gz档案中。到目前为止,我设法用以下代码实现了它,但是手动计算未压缩文件的大小并设置TarInfo的大小似乎很骇人,我想知道对于我的问题是否有更惯用的解决方案:< / p>

import gzip
import os
import pathlib
import tarfile

def gather_compressed_files(input_dir: pathlib.Path, output_file: str):
    with tarfile.open(output_file, 'w:gz') as tar:
        for input_file in input_dir.glob('*.gz'):
            with gzip.open(input_file) as fd:
                tar_info = tarfile.TarInfo(input_file.stem)
                tar_info.size = fd.seek(0, os.SEEK_END)
                fd.seek(0, os.SEEK_SET)
                tar.addfile(tar_info, fd)

我尝试通过以下方式创建TarInfo对象,而不是手动创建它:

tar_info = tar.gettarinfo(arcname=input_file.stem, fileobj=fd)

但是,此函数检索我们以.gz打开的原始fd文件的路径以计算其大小,因此仅提供与压缩后的{{1 }}数据,而不是未压缩的数据,这不是我想要的。完全不设置tar_info.size参数也不起作用,因为.gz在传递文件描述符时使用了上述大小。

是否有更好,更惯用的方式来实现这一目标?还是我坚持目前的解决方案?

1 个答案:

答案 0 :(得分:2)

您的方法是避免将文件完全解压缩到磁盘或RAM的唯一方法。毕竟,您需要提前知道要添加到tar文件中的大小,gzip个文件实际上并不知道它们自己的解压缩大小。 The ISIZE header field理论上提供了解压缩后的大小,但是该字段是在32位天中定义的,因此实际上是对2**32进行模运算的大小;一个原本大小为4 GB且文件大小为0 B的文件将具有相同的ISIZE。无论如何,Python不会公开ISIZE,所以即使有用,也没有内置的方法可以做到这一点(您总是可以手动解析,但这并不完全是干净的或惯用的)。

如果要避免两次解压缩文件(一次向前seek,一次将其实际添加到tar文件中),以将其解压缩到磁盘为代价,可以使用{{1} }稍加调整即可避免两次解压缩(无需将原始文件存储在内存中):

tempfile.TemporaryFile