问题描述
我有一个从 s3 下载的 tar.gz 文件,我将它加载到内存中,我想添加一个文件夹并最终将其写入另一个 s3。
我一直在尝试不同的方法:
from io import BytesIO
import gzip
buffer = BytesIO(zip_obj.get()["Body"].read())
im_memory_tar = tarfile.open(buffer,mode='a')
上面出现错误:ReadError: invalid header
。
使用以下方法:
im_memory_tar = tarfile.open(fileobj=buffer,mode='a')
im_memory_tar.add(name='code_1',arcname='code')
内容似乎被覆盖了。
您知道将文件夹附加到 tar.gz 文件的好方法吗?
谢谢。
解决方法
很好地解释了问题 how-to-append-a-file-to-a-tar-file-use-python-tarfile-module
请注意,'a:gz' 或 'a:bz2' 是不可能的。如果 mode 不适合打开某个(压缩)文件进行读取,则会引发 ReadError。使用模式 'r' 来避免这种情况。如果不支持压缩方法,则会引发 CompressionError。
,首先我们需要考虑如何附加到 tar 文件中。让我们暂时搁置压缩。
一个 tar 文件由两个全零的 512 字节块终止。要添加更多条目,您需要删除或覆盖最后的 1024 个字节。如果您随后在那里附加另一个 tar 文件,或者开始在那里写入一个新的 tar 文件,您将拥有一个包含原始两个条目的单个 tar 文件。
现在我们回到 tar.gz。您可以简单地解压缩整个 .gz 文件,按照上述方法进行追加,然后重新压缩整个文件。
避免解压缩和重新压缩相当困难,因为我们必须以某种方式从压缩流的末尾删除最后 1024 个字节的零。这是可能的,但您需要了解 deflate 压缩流的内部结构。
deflate 流由一系列压缩数据“块”组成,每个块的长度为任意位数。您需要在不写出结果的情况下解压缩,直到到达包含最后 1024 个字节的块。您需要保存该块和任何后续块的解压缩结果,以及该块开始的流中的位。然后您可以重新压缩该数据,从该字节开始,去掉最后 1024 个字节。
完成压缩,写出gzip预告片,去掉CRC和长度的1024个零。 (有一种方法可以从 CRC 中删除零。)现在您有一个完整的 gzip 流,用于前一个 .tar.gz 文件,但删除了最后 1024 个字节的零。
由于两个 gzip 流的连接本身就是一个有效的 gzip 流,您现在可以直接连接第二个 .tar.gz 文件或在那里开始写入新的 .tar.gz 流。您现在有一个单一的、有效的 .tar.gz 流,其中包含来自两个原始来源的条目。