就地修改 gzip 文件

In-place modification of gzip files

我需要修改一个 gzip 制表符分隔文件。我可以从输入中读取并将修改后的读取写入输出文件,如下所示:

output = tempfile.NamedTemporaryFile(mode="w", delete=False)
with gzip.open(input, "rb") as in_file,\
     gzip.open(output, "wb") as out_file:
    for l in in_file:
        split_line = l.split("\t")
        if split_line[0] == "hello":
            split_line[0] = "hi"
        out_file.write("\t".join(split_line))

我使用的 gzip 文件有 100 GB 规模,因此将整个文件重写到另一个文件只是为了修改一个子集并不理想。因此,我对修改文件 就地 的解决方案感兴趣(即,在遍历文件时修改原始文件)。

对于普通的 gzip 文件,当然不是。您唯一的选择是将 gzip 文件读取到您想要修改的位置,进行修改,然后重新压缩其余部分。在进行切割的地方需要注意,删除包含切割的放气块,然后从那里重新压缩,将剩余的放气块附加到正确的位位置。

理论上,您可以准备一个大的 gzip 文件,以便就地进行此类修改。您需要将 gzip 文件分解为独立的块,其中每个块开头的历史记录将被丢弃。 (pigz 使用 --independent 选项执行此操作。)您还需要在每个独立块的末尾插入几个空块或其他填充物 space 以允许独立块长度的变化,因此修改后的结果可以放回完全相同的字节数。您可以插入 5 个字节和 2 个字节的空块,如果您有足够的字节数,它们的组合应该能够容纳任何少量的字节数差异。

您将需要这些独立块的位置的单独索引,否则您将花费​​时间搜索它们,再次使时间取决于文件的长度。

为了不显着影响 gzip 文件的整体压缩率,您可能希望独立块的未压缩大小为 128K 字节或更大。任何修改都需要重新压缩整个独立块。

您还需要更新 gzip 文件末尾的 CRC 和长度。我认为有一种方法可以更新 CRC 而无需为整个文件重新计算它,但我必须考虑一下。如果文件的长度没有改变当然是可以的,但是如果你插入或删除字节,它会变得更棘手。

尝试将方形 gzip 钉放入圆形随​​机修改孔中将需要大量工作。它表明您只是为应用程序使用了错误的格式。为您想做的事情寻找不同的格式。