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

时间:2009-09-07 14:33:56

标签: python tar

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

我正在寻找一种避免两次传递的方法,首先将所有数据写入临时文件,然后将结果插入tarfile中。

基本上我执行以下操作(其中generator_encryptor是一个简单的生成器,它生成从源文件读取的数据块)。 :

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()

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

有任何暗示如何做到这一点?

4 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:2)

咦?你不能只使用subprocess模块来运行tar到tar吗?这样,就不需要临时文件了。当然,如果您无法以足够小的块生成数据以适应RAM,这将无法工作,但如果您遇到此问题,则tar不是问题。

答案 2 :(得分:2)

基本上使用类似文件的对象并将其传递给TarFile.addfile可以解决问题,但仍然存在一些问题。

  • 我需要知道开头的完整加密文件大小
  • tarfile访问read方法的方式是自定义类文件对象必须始终返回完整的读缓冲区,或者tarfile假设它是文件的结尾。它会在read方法的代码中导致一些非常低效的缓冲区复制,但它或者是更改tarfile模块。

结果代码如下,基本上我必须编写一个包装类,将我现有的生成器转换为类文件对象。我还在我的示例中添加了GeneratorEncrypto类以使代码完成。您可以注意到它有一个len方法,它返回写入文件的长度(但要理解它只是一个没有用处的虚拟占位符)。

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()

答案 3 :(得分:1)

我想你需要了解tar格式的工作原理,并自己处理tar写法。也许这会有所帮助?

http://mail.python.org/pipermail/python-list/2001-August/100796.html