بيثون كتابة سلسلة مباشرة إلى tarfile
سؤال
هل هناك طريقة لكتابة سلسلة مباشرة إلى tarfile؟ من http://docs.python.org/library/tarfile.html. يبدو أن الملفات فقط مكتوبة بالفعل إلى نظام الملفات يمكن إضافتها.
المحلول
أود أن أقول أنه من الممكن، من خلال اللعب مع Tarinfo e Tarfile.Addfile تمر Stringio كعلفي.
خشنة جدا، ولكن يعمل
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()
نصائح أخرى
كما أشار ستيفانو، يمكنك استخدام TarFile.addfile
و 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()
ربما ترغب في ملء مجالات أخرى من tarinfo
(على سبيل المثال mtime
, uname
الخ) كذلك.
لقد وجدت أن هذا يبحث عن كيفية الخدمة في django تم إنشاؤه للتو في أرشيف الذاكرة .tgz، قد يكون شخص آخر سيجد رمزي مفيد:
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
فقط للتسجيل:
كائنات Stringio لها خاصية .LEN.
لا حاجة للبحث (0) و do len (foo.buf)
لا حاجة للحفاظ على السلسلة بأكملها إلى فعل لين () أو لا سمح الله، هل يحقئ نفسك.
(ربما لم يحدث في وقت كتابة المرجع.)
يجب عليك استخدام كائنات Tarinfo وطريقة AddFile بدلا من طريقة الإضافة المعتادة:
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))
في حالتي، أردت أن أقرأ من ملف قارف موجود، إلحاق بعض البيانات إلى المحتويات، واكتبها إلى ملف جديد. شيء مثل:
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)
هناك حاجة إلى رمز إضافي لمعالجة الدلائل والروابط.
الحل في Python 3 يستخدم io.BytesIO
. وبعد تأكد من تعيين TarInfo.size
إلى طول البايتات، وليس طول السلسلة.
بالنظر إلى سلسلة واحدة، فإن أبسط الحل هو الاتصال .encode()
على ذلك للحصول على بايت. في هذا اليوم وهذا العصر، ربما تريد UTF-8، ولكن إذا كان المستلم يتوقع ترميزا محددا، مثل ASCII (أي أحرف متعددة البايات)، فاستخدم ذلك بدلا من ذلك.
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))
إذا كنت حقا بحاجة قابلة للكتابة سلسلة المخزن المؤقت، مشابه للإجابة المقبولة من SteFano Borini for Python 2، ثم الحل هو استخدام io.TextIOWrapper
على الأساسي io.BytesIO
متعادل.
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)