pitone stringa scrittura direttamente TarFile
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.
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)