Pergunta

Existe uma maneira de escrever uma string diretamente para um arquivo tar? De http://docs.python.org/library/tarfile.html parece que única já arquivos escritos no sistema de arquivos podem ser adicionados.

Foi útil?

Solução

Eu diria que é possível, por jogar com TarInfo e TarFile.addfile passando um StringIO como um FileObject.

Muito áspero, mas funciona

import tarfile
import StringIO

tar = tarfile.TarFile("test.tar","w")

string = StringIO.StringIO()
string.write("hello")
string.seek(0)
info = tarfile.TarInfo(name="foo")
info.size=len(string.buf)
tar.addfile(tarinfo=info, fileobj=string)

tar.close()

Outras dicas

Como Stefano apontou, você pode usar TarFile.addfile e StringIO.

import tarfile, StringIO

data = 'hello, world!'

tarinfo = tarfile.TarInfo('test.txt')
tarinfo.size = len(data)

tar = tarfile.open('test.tar', 'a')
tar.addfile(tarinfo, StringIO.StringIO(data))
tar.close()

Você provavelmente vai querer preencher outros campos da tarinfo (por exemplo mtime, uname etc.) bem.

Eu encontrei esta olhando como servir em Django um recém-criado no arquivo de memória .tgz, pode ser alguém vai encontrar a minha útil código:

import tarfile
from io import BytesIO


def serve_file(request):
    out = BytesIO()
    tar = tarfile.open(mode = "w:gz", fileobj = out)
    data = 'lala'.encode('utf-8')
    file = BytesIO(data)
    info = tarfile.TarInfo(name="1.txt")
    info.size = len(data)
    tar.addfile(tarinfo=info, fileobj=file)
    tar.close()

    response = HttpResponse(out.getvalue(), content_type='application/tgz')
    response['Content-Disposition'] = 'attachment; filename=myfile.tgz'
    return response

Apenas para o registro:
objetos StringIO tem uma propriedade .LEN.
Não há necessidade de procurar (0) e não len (foo.buf)
Não há necessidade de manter toda a cadeia em torno de que len () em, ou Deus me livre, fazer a contabilidade-se.

(Talvez isso não aconteceu na época do OP foi escrito.)

Você tem que usar TarInfo objetos eo método addfile em vez do método add habitual:

from StringIO import StringIO
from tarfile import open, TarInfo

s = "Hello World!"
ti = TarInfo("test.txt")
ti.size = len(s)

tf = open("testtar.tar", "w")
tf.addfile(ti, StringIO(s))

No meu caso eu queria ler de um arquivo tar existente, acrescentar alguns dados para o conteúdo, e escrevê-lo para um novo arquivo. Algo como:

for ti in tar_in:
    buf_in = tar.extractfile(ti)
    buf_out = io.BytesIO()
    size = buf_out.write(buf_in.read())
    size += buf_out.write(other data)
    buf_out.seek(0)
    ti.size = size
    tar_out.addfile(ti, fileobj=buf_out)
é necessário

código extra para a manipulação de diretórios e links.

A solução em Python 3 usos io.BytesIO. Certifique-se de conjunto TarInfo.size ao comprimento dos bytes, e não o comprimento da corda.

Dada uma única corda, a solução mais simples é chamar .encode() sobre ele para obter bytes. Neste dia e idade, você provavelmente quer UTF-8, mas se o destinatário está esperando uma codificação específica, tais como ASCII (ou seja, sem caracteres multi-byte), em seguida, utilizá-lo.

import io
import tarfile

data = 'hello\n'.encode('utf8')
info = tarfile.TarInfo(name='foo.txt')
info.size = len(data)

with tarfile.TarFile('test.tar', 'w') as tar:
    tar.addfile(info, io.BytesIO(data))

Se você realmente precisa de um gravável string tampão, similar à resposta aceito por @Stefano Borini para Python 2, então a solução é usar io.TextIOWrapper sobre um tampão io.BytesIO subjacente.

import io
import tarfile

textIO = io.TextIOWrapper(io.BytesIO(), encoding='utf8')
textIO.write('hello\n')
bytesIO = textIO.detach()
info = tarfile.TarInfo(name='foo.txt')
info.size = bytesIO.tell()

with tarfile.TarFile('test.tar', 'w') as tar:
    bytesIO.seek(0)
    tar.addfile(info, bytesIO)
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top