如何在不使用临时文件的情况下用python在tarfile中写入大量数据

如何在不使用临时文件的情况下用python在tarfile中写入大量数据,python,tar,Python,Tar,我用python编写了一个小的加密模块,其任务是对文件进行加密并将结果放入一个文件中。要加密的原始文件可以很大,但这不是问题,因为我的程序一次只需要处理一小块数据,这些数据可以动态加密和存储 我正在寻找一种方法来避免分两次完成,首先将所有数据写入一个临时文件,然后将结果插入一个文件 基本上我做了以下工作(generator_encryptor是一个简单的生成器,它生成从sourcefile读取的数据块)。 : 我有点恼火在归档时不得不使用临时文件直接在tar文件中编写blocs应该很容易,但是在

我用python编写了一个小的加密模块,其任务是对文件进行加密并将结果放入一个文件中。要加密的原始文件可以很大,但这不是问题,因为我的程序一次只需要处理一小块数据,这些数据可以动态加密和存储

我正在寻找一种方法来避免分两次完成,首先将所有数据写入一个临时文件,然后将结果插入一个文件

基本上我做了以下工作(generator_encryptor是一个简单的生成器,它生成从sourcefile读取的数据块)。 :

我有点恼火在归档时不得不使用临时文件直接在tar文件中编写blocs应该很容易,但是在单个字符串中收集每个块并使用类似于t.addfile('content',StringIO(bigcipheredstring))的东西似乎被排除在外,因为我不能保证我有足够的内存来处理旧的bigcipheredstring


有什么提示吗?

我想您需要了解tar格式是如何工作的,并自己编写tar。也许这会有所帮助


您可以创建自己的类文件对象并传递到TarFile.addfile。类文件对象将在fileobj.read()中动态生成加密内容方法。

嗯?难道你不能用这个模块来运行一条通向tar的管道吗?那样的话,就不需要临时文件。当然,如果你不能生成足够小的数据块来容纳RAM,这将不起作用,但是如果你有这个问题,那么tar就不是问题。

基本上使用类似文件的对象并将其传递给TarFile.ad虽然我们可以做到这一点,但仍有一些问题有待解决

  • 我需要在开始时知道完整的加密文件大小
  • tarfile访问读取方法的方式是,自定义的类似文件的对象必须始终返回完整的读取缓冲区,或者tarfile(假设它是文件的结尾)。这会导致读取方法的代码中出现一些非常低效的缓冲区复制,但要么如此,要么更改tarfile模块
生成的代码如下所示,基本上我必须编写一个包装类,将现有生成器转换为类似文件的对象。我还在示例中添加了GeneratorEncrypto类,以使代码完整。您可以注意到,它有一个len方法,返回编写的文件的长度(但请理解它只是一个没有任何用处的虚拟占位符)

导入文件
类生成器加密程序(对象):
“用于测试目的的虚拟类”
真正的加密程序对源文件执行即时加密
"""
定义初始化(自身,源):
self.source=源
self.BLOCKSIZE=1024
self.NBBLOCKS=1000
定义呼叫(自我):
对于范围内的c(0,self.NBBLOCKS):
收益率自块大小*str(c%10)
定义(自我):
返回self.BLOCKSIZE*self.NBBLOCKS
类生成器文件(对象):
“”“将数据生成器转换为常规文件句柄
"""
定义初始化(自身,生成器):
self.buf=“”
self.generator=generator()
def读取(自身,大小):
chunk=self.buf
而len(chunk)
读入库中的tarfile.py。如果我读对了,file对象必须实现的就是.Read()和.close()它会起作用的。似乎很容易。如果有效的话,我会尝试返回一个post列表。我看到您必须解决的唯一问题是,您必须在开始之前传递完整的加密文件大小,并返回正确大小的块,但我想您可以影响这一点。在.read()中返回小于请求大小也是有效的。如果用编程语言更容易表达并发性,则只需创建一个管道(os.pipe()),将读取端传递给addfile,并将写入端传递给输入端。然而,我认为这是一个复杂的失败,因为您必须设置不同的线程或进程来读取和写入。关键是要避免子进程。我需要完整的python异常管理。我不想解析stderr来了解tar失败的原因(包括磁盘空间不足、无法打开新进程等)。在查看tarfile.py源代码后,似乎很容易更改其预期读取总是返回完整缓冲区的行为。我可能会将其作为错误填充,并提出一个纠正补丁。如果底层tarfile作为真实文件打开,并且您可以四处移动(即:不是始终向前的流)。这只意味着写入两次tarfinfo头,因为tarinfo是在内容之前写入的。它还需要对tarfile模块(或某些派生类)进行一些更改。
t = tarfile.open("target.tar", "w")
tmp = file('content', 'wb')
for chunk in generator_encryptor("sourcefile"):
   tmp.write(chunks)
tmp.close()
t.add(content)
t.close()
import tarfile

class GeneratorEncryptor(object):
    """Dummy class for testing purpose

       The real one perform on the fly encryption of source file
    """
    def __init__(self, source):
        self.source = source
        self.BLOCKSIZE = 1024
        self.NBBLOCKS = 1000

    def __call__(self):
        for c in range(0, self.NBBLOCKS):
            yield self.BLOCKSIZE * str(c%10)

    def __len__(self):
        return self.BLOCKSIZE * self.NBBLOCKS

class GeneratorToFile(object):
    """Transform a data generator into a conventional file handle
    """
    def __init__(self, generator):
        self.buf = ''
        self.generator = generator()

    def read(self, size):
        chunk = self.buf
        while len(chunk) < size:
            try:
                chunk = chunk + self.generator.next()
            except StopIteration:
                self.buf = ''
                return chunk
        self.buf = chunk[size:]
        return chunk[:size]

t = tarfile.open("target.tar", "w")
tmp = file('content', 'wb')
generator = GeneratorEncryptor("source")
ti = t.gettarinfo(name = "content")
ti.size = len(generator)
t.addfile(ti, fileobj = GeneratorToFile(generator))
t.close()