如何使用Python 3正确操作内存中的tar文件?

2024-05-26 09:19:02 发布

您现在位置:Python中文网/ 问答频道 /正文

我需要完全在内存中更新tar存档。原因是我有一个与tar文件(包含敏感数据)的加密包,我无法将未加密的表单(tar存档)保存到磁盘。 现在,我能够很好地阅读它,但是保存新文件会导致意外的结果

在此主题中将不再讨论加密。这只是一个简短的描述,说明我需要以我现在的方式做事

我的目标是打开一个tar文件,从中删除一些文件,添加一些其他文件并保存新的.tar文件。 我需要使用BytesIO对象来完成它。但在一个简单得多的场景中,我甚至无法从以前的tar文件创建新的tar文件

在磁盘上读取和保存(复制)tar文件的简单方案:

$ ls -l
-rw-r--r-- 1 myuser myuser 3595 Jun  3 23:10 archive.pem
-rw-r--r-- 1 myuser myuser   50 Jun  3 23:19 gibberish
-rw-r--r-- 1 myuser myuser 1024 Jun  3 13:07 some_file.log

$ tar cfz example.tar.gz *
$ ls -l
-rw-r--r-- 1 myuser myuser 3595 Jun  3 23:10 archive.pem
-rw-r--r-- 1 myuser myuser 3059 Jun  4 09:08 example.tar.gz
-rw-r--r-- 1 myuser myuser   50 Jun  3 23:19 gibberish
-rw-r--r-- 1 myuser myuser 1024 Jun  3 13:07 some_file.log
$ tar tfz example.tar.gz
archive.pem
gibberish
some_file.log

使用简单的Python代码读取example.tar.gz并保存一个新的example.tar(只是一个副本):

import tarfile
with tarfile.open('example.tar.gz', 'r') as tr, tarfile.open('example.tar', 'w') as tw: 
    for m in tr.getmembers(): 
        print(f"{m.name} size = {m.size}") 
        tw.addfile(m)

运行此代码的输出为:

archive.pem size = 3595
gibberish size = 50
some_file.log size = 1024

新目录如下所示:

$ ls -l
-rw-r--r-- 1 myuser myuser  3595 Jun  3 23:10 archive.pem
-rw-r--r-- 1 myuser myuser 10240 Jun  4 09:16 example.tar
-rw-r--r-- 1 myuser myuser  3059 Jun  4 09:08 example.tar.gz
-rw-r--r-- 1 myuser myuser    50 Jun  3 23:19 gibberish
-rw-r--r-- 1 myuser myuser  1024 Jun  3 13:07 some_file.log
$ tar tf example.tar       
some_file.log

只列出一个文件,新tar文件的大小始终为10k。 文件的大部分都用“\0”字节填充

如果上述代码工作正常,作为一个简化示例,我真正想做的是:

通过删除一个文件并添加另一个文件来更新存档:

import tarfile
from io import BytesIO


def _update_tar(tarfileobj, file_to_add, file_to_remove):
    outio = BytesIO()

    with tarfile.open(fileobj=tarfileobj) as _in, tarfile.TarFile(
        fileobj=outio, mode="w"
    ) as _out:
        for member in _in.getmembers():
            print(f"Read {member.name} from archive.")
            if member.name != file_to_remove:
                print(f"Add {member.name} to the new archive!")
                _out.addfile(member)
        _out.add(file_to_add)
    outio.seek(0)
    return outio


tarbytes = open(
    "example.tar.gz", "rb"
).read()  # Those bytes will come from a decrypt function
input_io = BytesIO(tarbytes)

output_io = _update_tar(input_io, "new_file.txt", "gibberish")

with open("example.tar", "wb") as file: # Those bytes will go to an encrypt func
    file.write(output_io.read())
$ echo "Just a simple new file" >  new_file.txt
$ ls -l
-rw-r--r-- 1 myuser myuser  3595 Jun  3 23:10 archive.pem
-rw-r--r-- 1 myuser myuser  3059 Jun  4 09:08 example.tar.gz
-rw-r--r-- 1 myuser myuser    50 Jun  3 23:19 gibberish
-rw-r--r-- 1 myuser myuser    23 Jun  4 09:45 new_file.txt
-rw-r--r-- 1 myuser myuser  1024 Jun  3 13:07 some_file.log
-rw-r--r-- 1 myuser myuser   813 Jun  4 09:46 updatetar.py
$ python updatetar.py
Read archive.pem from archive.
Add archive.pem to the new archive!
Read gibberish from archive.
Read some_file.log from archive.
Add some_file.log to the new archive!
$ ls -l
-rw-r--r-- 1 myuser myuser  3595 Jun  3 23:10 archive.pem
-rw-r--r-- 1 myuser myuser 10240 Jun  4 09:46 example.tar
-rw-r--r-- 1 myuser myuser  3059 Jun  4 09:08 example.tar.gz
-rw-r--r-- 1 myuser myuser    50 Jun  3 23:19 gibberish
-rw-r--r-- 1 myuser myuser    23 Jun  4 09:45 new_file.txt
-rw-r--r-- 1 myuser myuser  1024 Jun  3 13:07 some_file.log
-rw-r--r-- 1 myuser myuser   813 Jun  4 09:46 updatetar.py

结果是一样的。正在生成此10K文件

我正在Linux机器上使用Python 3.8.3

谁能帮我找到用Python更新内存中tar文件的正确方法


Tags: 文件tolognewexamplesometarpem