Python schreibt String direkt in Tarfile
Frage
Gibt es eine Möglichkeit, einen String direkt in eine Tarfile zu schreiben?Aus http://docs.python.org/library/tarfile.html Es sieht so aus, als ob nur Dateien hinzugefügt werden können, die bereits in das Dateisystem geschrieben wurden.
Lösung
Ich würde sagen, es ist möglich, durch das Spiel mit TarInfo e TarFile.addfile eine StringIO als Fileobject übergeben.
Sehr rau, aber Werke
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()
Andere Tipps
Wie Stefano wies darauf hin, können Sie TarFile.addfile
und StringIO
verwenden.
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()
Sie wollen wahrscheinlich auch andere Felder von tarinfo
(z mtime
, uname
etc.) als auch füllen.
Ich fand diese Suche wie in Django dienen ein nur im Speicher TGZ-Archiv erstellt, kann jemand anderes meinen Code nützlich finden:
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
Nur für das Protokoll:
StringIO-Objekte haben eine .len-Eigenschaft.
Es ist nicht nötig, „seeke(0)“ und „len(foo.buf)“ auszuführen.
Sie müssen nicht die gesamte Zeichenfolge bereithalten, um len() auszuführen, oder Gott bewahre, Sie müssen die Abrechnung selbst durchführen.
(Vielleicht war das zum Zeitpunkt der Erstellung des OP noch nicht der Fall.)
Sie haben TarInfo Objekte und die AddFile Methode anstelle der üblichen Anbaumethode verwenden:
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))
In meinem Fall wollte ich aus einer vorhandenen tar-Datei lesen, einige Daten zu den Inhalten anzuhängen, und schreiben Sie es in eine neue Datei. So etwas wie:
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)
Zusatzcode ist erforderlich für Verzeichnisse und Links Handhabung.
Die Lösung in Python 3 verwendet io.BytesIO
. Achten Sie darauf, TarInfo.size
auf die Länge des Bytes zu setzen, nicht die Länge der Zeichenfolge.
eine einzelne Saite gegeben, ist die einfachste Lösung .encode()
darauf zu nennen Bytes zu erhalten. In der heutigen Zeit wollen Sie wahrscheinlich UTF-8, aber wenn der Empfänger eine bestimmte Codierung, wie ASCII erwartet (das heißt kein Multi-Byte-Zeichen), dann ist das stattdessen verwendet werden.
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))
Wenn Sie wirklich brauchen eine beschreibbare string Puffer, ähnlich wie die akzeptierten Antwort von @Stefano Borini für Python 2 ist, dann ist die Lösung io.TextIOWrapper
über einen darunter liegenden io.BytesIO
Puffer verwenden.
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)