Domanda

C'è un modo per scrivere una stringa direttamente ad un tarfile? Da http://docs.python.org/library/tarfile.html sembra solo i file già scritto al file system può essere aggiunto.

È stato utile?

Soluzione

Vorrei dire che è possibile, giocando con TarInfo e TarFile.addfile passando uno StringIO come FileObject.

Molto ruvido, ma lavori

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

Altri suggerimenti

Come Stefano ha sottolineato, è possibile utilizzare 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()

Probabilmente si vorrà riempire altri campi di tarinfo (ad esempio mtime, uname ecc) pure.

Ho trovato questo guardando come servire in Django un solo creato nell'archivio .tgz di memoria, potrebbe essere qualcun altro troverà il mio codice utile:

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

Solo per la cronaca:
oggetti StringIO hanno una proprietà .LEN.
Non c'è bisogno di cercare (0) e fare len (foo.buf)
Non c'è bisogno di mantenere l'intera stringa intorno al fare len () su, o Dio non voglia, fare la contabilità te stesso.

(Forse non ha al momento il PO è stato scritto.)

È necessario utilizzare gli oggetti TarInfo e il metodo addfile invece del solito metodo add:

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

Nel mio caso ho voluto leggere da un file tar esistente, aggiungere alcuni dati ai contenuti, e lo scrive in un nuovo file. Qualcosa di simile:

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

Codice extra per la gestione di directory e collegamenti.

La soluzione in Python 3 utilizza io.BytesIO. Assicurarsi di impostare TarInfo.size alla lunghezza dei byte, non la lunghezza della stringa.

Data una singola stringa, la soluzione più semplice è chiamare .encode() su di esso per ottenere byte. In questo giorno di età e probabilmente si desidera UTF-8, ma se il destinatario si aspetta una codifica specifica, come ad esempio ASCII (vale a dire senza caratteri multi-byte), quindi utilizzare che, invece.

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 davvero avete bisogno di uno scrivibile stringa di buffer, simile alla risposta accettata dalla @Stefano Borini per Python 2, allora la soluzione è quella di utilizzare io.TextIOWrapper su un buffer io.BytesIO sottostante.

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)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top