Как программно создать tar-архив вложенных каталогов и файлов исключительно из строк Python и без временных файлов? - PullRequest
4 голосов
/ 28 декабря 2011

Я хочу создать tar-архив с иерархической структурой каталогов из Python, используя строки для содержимого файлов. Я прочитал этот вопрос , который показывает способ добавления строк в виде файлов, но не в виде каталогов. Как я могу добавить каталоги на лету в архив tar без фактического их создания?

Что-то вроде:

archive.tgz:
    file1.txt
    file2.txt
    dir1/
        file3.txt
        dir2/
            file4.txt

Ответы [ 3 ]

10 голосов
/ 28 декабря 2011

Расширяя пример, приведенный в связанном вопросе, вы можете сделать это следующим образом:

import tarfile
import StringIO
import time

tar = tarfile.TarFile("test.tar", "w")

string = StringIO.StringIO()
string.write("hello")
string.seek(0)

info = tarfile.TarInfo(name='dir')
info.type = tarfile.DIRTYPE
info.mode = 0755
info.mtime = time.time()
tar.addfile(tarinfo=info)

info = tarfile.TarInfo(name='dir/foo')
info.size=len(string.buf)
info.mtime = time.time()
tar.addfile(tarinfo=info, fileobj=string)

tar.close()

Будьте осторожны с атрибутом mode, так как значение по умолчанию может не включать разрешения на выполнение для владельца каталога, которыйнеобходимо изменить его и получить его содержимое.

1 голос
/ 28 декабря 2011

Глядя на формат файла tar , это кажется выполнимым.Файлы, которые идут в каждом подкаталоге, получают в качестве своего имени относительный путь (например, dir1/file3.txt).

Единственная хитрость заключается в том, что вы должны определить каждый каталог перед файлами, которые в него входят (tar won 'создать необходимые подкаталоги на лету).Существует специальный флаг, который можно использовать для идентификации записи в файле tarfile как каталога, но в устаревших целях tar также принимает записи файлов с именами, которые заканчиваются на /, в качестве каталогов, поэтому вы можете просто добавить dir1/ как файл из строки нулевой длины, используя ту же технику.

0 голосов
/ 06 июля 2019

Небольшое изменение к полезному принятому ответу , так что оно работает как с питоном 3, так и с питоном 2 (и немного ближе соответствует примеру ОП):

from io import BytesIO
import tarfile
import time

# create and open empty tar file
tar = tarfile.open("test.tgz", "w:gz")

# Add a file
file1_contents = BytesIO("hello 1".encode())
finfo1 = tarfile.TarInfo(name='file1.txt')
finfo1.size = len(file1_contents.getvalue())
finfo1.mtime = time.time()
tar.addfile(tarinfo=finfo1, fileobj=file1_contents)

# create directory in the tar file
dinfo = tarfile.TarInfo(name='dir')
dinfo.type = tarfile.DIRTYPE
dinfo.mode = 0o755
dinfo.mtime = time.time()
tar.addfile(tarinfo=dinfo)

# add a file to the new directory in the tar file
file2_contents = BytesIO("hello 2".encode())
finfo2 = tarfile.TarInfo(name='dir/file2.txt')
finfo2.size = len(file2_contents.getvalue())
finfo2.mtime = time.time()
tar.addfile(tarinfo=finfo2, fileobj=file2_contents)

tar.close()

В частности, я обновил восьмеричный синтаксис после PEP 3127 - Поддержка целочисленных литералов и синтаксис , переключен на BytesIO from io, использовал getvalue вместо buf и использовал open вместо TarFile, чтобы показать сжатый вывод как в примере. (Использование обработчика контекста (with ... as tar:) также работало бы как в python2, так и в python3, но вырезка и вставка не работали с моим repthon python2, поэтому я не переключал его.) Протестировано на python 2.7.15+ и python 3.7 0,3.

...