解压缩 .gz 文件并将它们存储在 .tar.gz 存档中

Posted

技术标签:

【中文标题】解压缩 .gz 文件并将它们存储在 .tar.gz 存档中【英文标题】:Uncompressing .gz files and storing them in a .tar.gz archive 【发布时间】:2019-01-02 15:08:40 【问题描述】:

我有以下问题:我正在编写一个函数来查找一堆 .gz 文件,解压缩它们,并将单独的未压缩文件存储在更大的 .tar.gz 存档中。到目前为止,我设法使用以下代码实现它,但手动计算未压缩文件大小并设置 TarInfo 大小似乎相当hackish,我想知道是否有更惯用的解决方案来解决我的问题:

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)

然而,这个函数检索我们以fd打开的原始.gz文件的路径来计算它的大小,因此只提供一个tar_info.size参数对应于压缩的.gz数据而不是未压缩的数据,这不是我想要的。根本不设置tar_fino.size 参数也不起作用,因为addfile 在传递文件描述符时使用所述大小。

有没有更好、更惯用的方法来实现这一点,还是我坚持目前的解决方案?

【问题讨论】:

你能举个例子来说明你的尝试吗?所有这些tar.gz 文件是否都存储在一个目录中?是否要将所有这些文件合并到一个 tar.gz 文件中?我只是在验证,所以我正确理解了您的问题。 我有一个包含.gz 文件的目录,我尝试将这些文件单独未压缩地存储在.tar.gz 文件中。 【参考方案1】:

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

如果你想避免两次解压文件(一次到seek转发,一次实际添加到tar文件),以解压到磁盘为代价,你可以使用tempfile.TemporaryFile来避免两次稍作调整即可解压(无需将原始文件存储在内存中):

import shutil
import tempfile

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 tempfile.TemporaryFile() as tf:
                # Could combine both in one with, but this way we close the gzip
                # file ASAP
                with gzip.open(input_file) as fd:
                    shutil.copyfileobj(fd, tf)
                tar_info = tarfile.TarInfo(input_file.stem)
                tar_info.size = tf.tell()
                tf.seek(0)
                tar.addfile(tar_info, tf)

【讨论】:

感谢您的回答。 ISIZE 不能使用让我有点难过,但我想我们不能拥有我们想玩的所有玩具:)

以上是关于解压缩 .gz 文件并将它们存储在 .tar.gz 存档中的主要内容,如果未能解决你的问题,请参考以下文章

java 如何用zlib解压缩tar.gz文件

markdown [压缩/解压缩文件]压缩和解压缩.tar.gz文件#tar.gz #compress

Linux下*.tar.gz文件解压缩命令

Linux下*.tar.gz文件解压缩命令

如何在水壶中解压缩和导入 .tar.gz 文件?

linux中解压缩并安装.tar.gz后缀的文件