我遇到以下问题:我正在编写一个函数,该函数查找一堆.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
在传递文件描述符时使用了上述大小。
是否有更好,更惯用的方式来实现这一目标?还是我坚持目前的解决方案?
答案 0 :(得分:2)
您的方法是避免将文件完全解压缩到磁盘或RAM的唯一方法。毕竟,您需要提前知道要添加到tar文件中的大小,gzip
个文件实际上并不知道它们自己的解压缩大小。 The ISIZE
header field理论上提供了解压缩后的大小,但是该字段是在32位天中定义的,因此实际上是对2**32
进行模运算的大小;一个原本大小为4 GB且文件大小为0 B的文件将具有相同的ISIZE
。无论如何,Python不会公开ISIZE
,所以即使有用,也没有内置的方法可以做到这一点(您总是可以手动解析,但这并不完全是干净的或惯用的)。
如果要避免两次解压缩文件(一次向前seek
,一次将其实际添加到tar文件中),以将其解压缩到磁盘为代价,可以使用{{1} }稍加调整即可避免两次解压缩(无需将原始文件存储在内存中):
tempfile.TemporaryFile