Python 在不写入磁盘的情况下提取lzma压缩tar存档成员
我有一个2焦油深的嵌套焦油文件。最外层的tar是gpg加密的而不是压缩的。内部焦油是lzma。使用磁盘最里面的tar,我没有任何问题。使用tarfile.open()将最内部的tar.xz文件直接传递到Python 在不写入磁盘的情况下提取lzma压缩tar存档成员,python,lzma,tarfile,Python,Lzma,Tarfile,我有一个2焦油深的嵌套焦油文件。最外层的tar是gpg加密的而不是压缩的。内部焦油是lzma。使用磁盘最里面的tar,我没有任何问题。使用tarfile.open()将最内部的tar.xz文件直接传递到,就像get_lzma一样。该行后面的代码执行时不会出错。我可以提取tar成员和json.load()数据 这是一个小文件,数据很敏感。当我使用它时,它必须放在磁盘上,所以我不想解密它并将最里面的tar提取到磁盘上。所以我想访问内存中的成员。我可以解密到gpg文件,并在get_lzma.getme
,就像get_lzma
一样。该行后面的代码执行时不会出错。我可以提取tar成员和json.load()
数据
这是一个小文件,数据很敏感。当我使用它时,它必须放在磁盘上,所以我不想解密它并将最里面的tar提取到磁盘上。所以我想访问内存中的成员。我可以解密到gpg文件,并在get_lzma.getmembers()中为成员:
返回我期望的tarinfo对象,因此该成员似乎在那里,我对此无能为力。当我运行extractfile()
时,我无法读取它返回的结果
在这一点上,我只是好奇为什么这不起作用
如果文件结构不清楚,磁盘上就是这样的:
file.tar.gpg <- is a tar file
file.tar.xz <- is a compressed tar file
member1
memberN
离这个问题还有一天,我对这个问题的理解似乎就清楚了。我会解释我的想法和我的发现
tldr我把tarinfo、tarfile和exfileobjects搞混了
根据OP,传递到open()
的文件在封面下表示为
。因此,让代码处理未加密的文件和open()
,实际上只能证明文件没有损坏。所以没有问题,我不会再提了
按照OP中的代码示例,调用decrypted_data.data
从decrypted_data
对象返回原始字节字符串。这些原始字节是我的2个tar文件。解压tar和压缩tar嵌套结构。字符串以b'myfile.tar.xz\x00\x00\x00\.
等开头。我们将其包装为一个bytes对象io.BytesIO(decrypted_data.data)
,这样我们就有了一个可以使用的接口,并可以将其初始传递到tarfile.open()
。到目前为止还不错,但这就是事情开始出错的地方
我决定在下面的代码中使用2个上下文管理器。在OP中,我两次调用了tarfile.open()
,我想我一定假设有一个提取操作和mode='r'
。您可以看到,我现在在每个上下文管理器的成员上对extractfile()
进行了两次调用。第一个extractfile()
从未压缩的tar中提取tar.xz。这是我最终作为mode=r:xz
传递给下一个上下文管理器的ExFileObject
“文件”。在OP中,它是一个TarInfo
对象,而不是提取的数据,这是错误的
第二次调用extractfile()
是在第二个上下文管理器的member
上完成的,以便从myfile.tar.xz
获取可读的\u members\u值
with tarfile.open(fileobj=io_bytes_file_like_object, mode='r') as uncompressed_tar_file:
# uncompressed_tar_file is tarfile.TarFile object
for member in uncompressed_tar_file.getmembers():
# member is TarInfo object
tar_file_object = uncompressed_tar_file.extractfile(member)
# tar_file_object is ExFileObject
with tarfile.open(fileobj=tar_file_object, mode='r:xz', debug=3, errorlevel=2) as lzma_compressed_tar_file:
for member in lzma_compressed_tar_file.getmembers():
if member.isfile():
readable_members_value = lzma_compressed_tar_file.extractfile(member)
# now works where it failed before equivalent to something like file_o.read() in OP
print(readable_members_value.read())
decoded_readable_member_value = readable_member_value.read().decode("utf-8")
json_data = json.loads(decoded_readable_member_value)
print(json_data)
除了最后几行代码外,其余代码几乎完全相同。从OP中的变量名可以看出,我希望file\o
是一个文件对象json.load(file_o)
将对文件指针起作用,但在本例中,readable_成员。read()
返回字节文本b'
,因此实际上我不需要json.load()
with open(gpg_encrypted_tar_archive, 'rb') as f:
try:
decrypted_data = gpg.decrypt_file(f, passphrase=passph)
assert decrypted_data.ok
except AssertionError:
print(f"Decryption failed with message '{decrypted_data.status}' and status '{decrypted_data.ok}'")
io_bytes_file_like_object = io.BytesIO(decrypted_data.data)
# untar the parent archive
tarfile.open(fileobj=io_bytes_file_like_object, mode='r')
with tarfile.open(fileobj=io_bytes_file_like_object, mode='r:xz', debug=3, errorlevel=2) as get_lzma:
for member in get_lzma.getmembers():
if member.isfile():
file_o = get_lzma.extractfile(member)
json.load(file_o)
with tarfile.open(fileobj=io_bytes_file_like_object, mode='r') as uncompressed_tar_file:
# uncompressed_tar_file is tarfile.TarFile object
for member in uncompressed_tar_file.getmembers():
# member is TarInfo object
tar_file_object = uncompressed_tar_file.extractfile(member)
# tar_file_object is ExFileObject
with tarfile.open(fileobj=tar_file_object, mode='r:xz', debug=3, errorlevel=2) as lzma_compressed_tar_file:
for member in lzma_compressed_tar_file.getmembers():
if member.isfile():
readable_members_value = lzma_compressed_tar_file.extractfile(member)
# now works where it failed before equivalent to something like file_o.read() in OP
print(readable_members_value.read())
decoded_readable_member_value = readable_member_value.read().decode("utf-8")
json_data = json.loads(decoded_readable_member_value)
print(json_data)