Pregunta

¿Hay una manera de escribir una cadena directamente a un archivo tar? De http://docs.python.org/library/tarfile.html que parece Sólo ya archivos escritos en el sistema de archivos se puede añadir.

¿Fue útil?

Solución

Yo diría que es posible, jugando con TarInfo e TarFile.addfile pasar un StringIO como FileObject.

muy duro, pero 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()

Otros consejos

Como se señaló Stefano, puede utilizar TarFile.addfile y 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()

Es probable que desee rellenar otros campos de tarinfo (por ejemplo mtime, uname etc.) también.

Me pareció que esta buscando la forma de servir en una Django acaba de crear en el archivo .tgz de memoria, puede ser alguien más va a encontrar mi código muy útil:

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

Sólo para que conste:
StringIO objetos tienen una propiedad .LEN.
No hay necesidad de buscar (0) y hacer len (foo.buf)
No hay necesidad de mantener toda la cadena alrededor para hacer len () en, o Dios no lo quiera, haga lo que representa a sí mismo.

(Tal vez no lo hizo en el momento de la OP fue escrito.)

Usted tiene que usar objetos TarInfo y el método AddFile en lugar del 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))

En mi caso quería leer desde un archivo tar existente, añadir algunos datos a los contenidos, y escribirlo en un archivo nuevo. Algo así 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)
Se necesita

código adicional para el manejo de directorios y enlaces.

La solución en Python 3 utiliza io.BytesIO. Asegúrese de ajustar TarInfo.size a la longitud de los bytes, no la longitud de la cadena.

En vista de una sola cadena, la solución más sencilla es llamar .encode() en él para obtener bytes. En este día y edad es probable que desee UTF-8, pero si el receptor está esperando una codificación específica, tales como ASCII (es decir, no hay caracteres multi-byte), a continuación, utilice en su lugar.

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

Si realmente necesita un permiso de escritura cadena memoria intermedia, similar a la respuesta aceptada por @Stefano Borini para Python 2, entonces la solución es utilizar io.TextIOWrapper a través de una memoria intermedia io.BytesIO subyacente.

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 bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top