Рубрики
Без рубрики

tarfile – Доступ к архиву Tar

Автор оригинала: Doug Hellmann.

Цель:

Доступ к tar-архиву.

Модуль tarfile обеспечивает доступ для чтения и записи к архивам tar Unix, включая сжатые файлы. Помимо стандартов POSIX, поддерживаются несколько расширений GNU tar. Также обрабатываются специальные типы файлов Unix, такие как жесткие и программные ссылки, а также узлы устройств.

Примечание

Хотя tarfile реализует формат Unix, его также можно использовать для создания и чтения архивов tar в Microsoft Windows.

Тестирование файлов Tar

Функция is_tarfile () возвращает логическое значение, указывающее, относится ли имя файла, переданное в качестве аргумента, к допустимому архиву tar.

tarfile_is_tarfile.py

import tarfile

for filename in ['README.txt', 'example.tar',
                 'bad_example.tar', 'notthere.tar']:
    try:
        print('{:>15}  {}'.format(filename, tarfile.is_tarfile(
            filename)))
    except IOError as err:
        print('{:>15}  {}'.format(filename, err))

Если файл не существует, is_tarfile () вызывает IOError .

$ python3 tarfile_is_tarfile.py

     README.txt  False
    example.tar  True
bad_example.tar  False
   notthere.tar  [Errno 2] No such file or directory:
'notthere.tar'

Чтение метаданных из архива

Используйте класс TarFile для работы непосредственно с tar-архивом. Он поддерживает методы для чтения данных о существующих архивах, а также для изменения архивов путем добавления дополнительных файлов.

Чтобы прочитать имена файлов в существующем архиве, используйте getnames () .

tarfile_getnames.py

import tarfile

with tarfile.open('example.tar', 'r') as t:
    print(t.getnames())

Возвращаемое значение – это список строк с именами содержимого архива.

$ python3 tarfile_getnames.py

['index.rst', 'README.txt']

Помимо имен, метаданные об элементах архива доступны как экземпляры объектов TarInfo .

tarfile_getmembers.py

import tarfile
import time

with tarfile.open('example.tar', 'r') as t:
    for member_info in t.getmembers():
        print(member_info.name)
        print('  Modified:', time.ctime(member_info.mtime))
        print('  Mode    :', oct(member_info.mode))
        print('  Type    :', member_info.type)
        print('  Size    :', member_info.size, 'bytes')
        print()

Загрузите метаданные с помощью getmembers () и getmember () .

$ python3 tarfile_getmembers.py

index.rst
  Modified: Fri Aug 19 16:27:54 2016
  Mode    : 0o644
  Type    : b'0'
  Size    : 9878 bytes

README.txt
  Modified: Fri Aug 19 16:27:54 2016
  Mode    : 0o644
  Type    : b'0'
  Size    : 75 bytes

Если имя элемента архива известно заранее, его объект TarInfo можно получить с помощью getmember () .

tarfile_getmember.py

import tarfile
import time

with tarfile.open('example.tar', 'r') as t:
    for filename in ['README.txt', 'notthere.txt']:
        try:
            info  t.getmember(filename)
        except KeyError:
            print('ERROR: Did not find {} in tar archive'.format(
                filename))
        else:
            print('{} is {:d} bytes'.format(
                info.name, info.size))

Если элемент архива отсутствует, getmember () вызывает KeyError .

$ python3 tarfile_getmember.py

README.txt is 75 bytes
ERROR: Did not find notthere.txt in tar archive

Извлечение файлов из архива

Чтобы получить доступ к данным из элемента архива в программе, используйте метод extractfile () , передав имя элемента.

tarfile_extractfile.py

import tarfile

with tarfile.open('example.tar', 'r') as t:
    for filename in ['README.txt', 'notthere.txt']:
        try:
            f  t.extractfile(filename)
        except KeyError:
            print('ERROR: Did not find {} in tar archive'.format(
                filename))
        else:
            print(filename, ':')
            print(f.read().decode('utf-8'))

Возвращаемое значение – это объект в виде файла, из которого может быть прочитано содержимое члена архива.

$ python3 tarfile_extractfile.py

README.txt :
The examples for the tarfile module use this file and
example.tar as data.

ERROR: Did not find notthere.txt in tar archive

Чтобы распаковать архив и записать файлы в файловую систему, используйте вместо него extract () или extractall () .

tarfile_extract.py

import tarfile
import os

os.mkdir('outdir')
with tarfile.open('example.tar', 'r') as t:
    t.extract('README.txt', 'outdir')
print(os.listdir('outdir'))

Член или члены считываются из архива и записываются в файловую систему, начиная с каталога, указанного в аргументах.

$ python3 tarfile_extract.py

['README.txt']

Документация стандартной библиотеки включает примечание о том, что extractall () безопаснее, чем extract () , особенно для работы с потоковыми данными, когда перемотка для чтения более ранней части ввода невозможно, и его следует использовать в большинстве случаев.

tarfile_extractall.py

import tarfile
import os

os.mkdir('outdir')
with tarfile.open('example.tar', 'r') as t:
    t.extractall('outdir')
print(os.listdir('outdir'))

В extractall () первым аргументом является имя каталога, в который должны быть записаны файлы.

$ python3 tarfile_extractall.py

['README.txt', 'index.rst']

Чтобы извлечь определенные файлы из архива, передайте их имена или контейнеры метаданных TarInfo в extractall () .

tarfile_extractall_members.py

import tarfile
import os

os.mkdir('outdir')
with tarfile.open('example.tar', 'r') as t:
    t.extractall('outdir',
                 members[t.getmember('README.txt')],
                 )
print(os.listdir('outdir'))

Если предоставляется список members , извлекаются только названные файлы.

$ python3 tarfile_extractall_members.py

['README.txt']

Создание новых архивов

Чтобы создать новый архив, откройте TarFile в режиме 'w' .

tarfile_add.py

import tarfile

print('creating archive')
with tarfile.open('tarfile_add.tar', mode'w') as out:
    print('adding README.txt')
    out.add('README.txt')

print()
print('Contents:')
with tarfile.open('tarfile_add.tar', mode'r') as t:
    for member_info in t.getmembers():
        print(member_info.name)

Любой существующий файл обрезается и запускается новый архив. Чтобы добавить файлы, используйте метод add () .

$ python3 tarfile_add.py

creating archive
adding README.txt

Contents:
README.txt

Использование альтернативных имен членов архива

Можно добавить файл в архив, используя имя, отличное от исходного имени файла, создав объект TarInfo с альтернативным arcname и передав его в addfile ( ) .

tarfile_addfile.py

import tarfile

print('creating archive')
with tarfile.open('tarfile_addfile.tar', mode'w') as out:
    print('adding README.txt as RENAMED.txt')
    info  out.gettarinfo('README.txt', arcname'RENAMED.txt')
    out.addfile(info)

print()
print('Contents:')
with tarfile.open('tarfile_addfile.tar', mode'r') as t:
    for member_info in t.getmembers():
        print(member_info.name)

В архиве только измененное имя файла:

$ python3 tarfile_addfile.py

creating archive
adding README.txt as RENAMED.txt

Contents:
RENAMED.txt

Запись данных из источников, отличных от файлов

Иногда возникает необходимость записать данные в архив прямо из памяти. Вместо того, чтобы записывать данные в файл, а затем добавлять этот файл в архив, вы можете использовать addfile () для добавления данных из открытого файлового дескриптора, который возвращает байты.

tarfile_addfile_string.py

import io
import tarfile

text  'This is the data to write to the archive.'
data  text.encode('utf-8')

with tarfile.open('addfile_string.tar', mode'w') as out:
    info  tarfile.TarInfo('made_up_file.txt')
    info.size  len(data)
    out.addfile(info, io.BytesIO(data))

print('Contents:')
with tarfile.open('addfile_string.tar', mode'r') as t:
    for member_info in t.getmembers():
        print(member_info.name)
        f  t.extractfile(member_info)
        print(f.read().decode('utf-8'))

Создав сначала объект TarInfo , члену архива можно присвоить любое желаемое имя. После установки размера данные записываются в архив с использованием addfile () и буфера BytesIO в качестве источника данных.

$ python3 tarfile_addfile_string.py

Contents:
made_up_file.txt
This is the data to write to the archive.

Добавление в архив

Помимо создания новых архивов, можно добавить к существующему файлу, используя режим 'a' .

tarfile_append.py

import tarfile

print('creating archive')
with tarfile.open('tarfile_append.tar', mode'w') as out:
    out.add('README.txt')

print('contents:',)
with tarfile.open('tarfile_append.tar', mode'r') as t:
    print([m.name for m in t.getmembers()])

print('adding index.rst')
with tarfile.open('tarfile_append.tar', mode'a') as out:
    out.add('index.rst')

print('contents:',)
with tarfile.open('tarfile_append.tar', mode'r') as t:
    print([m.name for m in t.getmembers()])

Результирующий архив заканчивается двумя участниками:

$ python3 tarfile_append.py

creating archive
contents:
['README.txt']
adding index.rst
contents:
['README.txt', 'index.rst']

Работа со сжатыми архивами

Помимо обычных файлов архива tar, модуль tarfile может работать с архивами, сжатыми по протоколам gzip или bzip2. Чтобы открыть сжатый архив, измените строку режима, переданную в open () , чтобы включить ": gz" или ": bz2" , в зависимости от желаемый метод сжатия.

tarfile_compression.py

import tarfile
import os

fmt  '{:<30} {:<10}'
print(fmt.format('FILENAME', 'SIZE'))
print(fmt.format('README.txt', os.stat('README.txt').st_size))

FILES  [
    ('tarfile_compression.tar', 'w'),
    ('tarfile_compression.tar.gz', 'w:gz'),
    ('tarfile_compression.tar.bz2', 'w:bz2'),
]

for filename, write_mode in FILES:
    with tarfile.open(filename, modewrite_mode) as out:
        out.add('README.txt')

    print(fmt.format(filename, os.stat(filename).st_size),
          end' ')
    print([
        m.name
        for m in tarfile.open(filename, 'r:*').getmembers()
    ])

При открытии существующего архива для чтения укажите "r: *" , чтобы tarfile определял метод сжатия для автоматического использования.

$ python3 tarfile_compression.py

FILENAME                       SIZE
README.txt                     75
tarfile_compression.tar        10240      ['README.txt']
tarfile_compression.tar.gz     213        ['README.txt']
tarfile_compression.tar.bz2    199        ['README.txt']

Смотрите также