Tarfile.TarFile.extract: примеры (PYTHON)

Метод extract для работы с tar архивами в Python
Раздел: Архивы, Распаковка
tarfile.TarFile.extract(member, path, set_attrs): str

Описание функции tarfile.TarFile.extract

Метод extract() класса tarfile.TarFile предназначен для извлечения одного элемента из tar-архива в файловую систему. Он применяется при необходимости выборочной распаковки файлов или каталогов без обработки всего архива.

Сигнатура метода: extract(member, path="", set_attrs=True, *, numeric_owner=False)

Аргументы:

  • member (обязательный) - может быть объектом TarInfo или строкой с именем элемента в архиве. Определяет, какой файл или директорию требуется извлечь.
  • path (необязательный, по умолчанию "") - строка, указывающая путь в файловой системе, куда будет произведено извлечение. Если путь не задан, используется текущая рабочая директория.
  • set_attrs (необязательный, по умолчанию True) - булево значение. Если установлено в True, метод пытается сохранить метаданные элемента (время модификации, права доступа, владельца). В противном случае эти атрибуты игнорируются.
  • numeric_owner (необязательный, только именованный, по умолчанию False) - булево значение. При значении True владелец и группа устанавливаются по числовым идентификаторам (UID/GID) из архива. Если False, производится попытка использовать соответствующие имена пользователей и групп системы.

Возвращаемое значение: метод возвращает абсолютный путь к извлеченному файлу или директории в виде строки. Если извлечение не удалось, возникает исключение.

Базовые примеры использования

Пример извлечения файла по имени в текущую директорию:

import tarfile

with tarfile.open('archive.tar', 'r') as tar:
    tar.extract('document.txt')
    print('Файл извлечен')
Файл извлечен

Пример извлечения файла в указанный каталог с сохранением атрибутов:

import tarfile

with tarfile.open('archive.tar', 'r') as tar:
    extracted_path = tar.extract('image.jpg', path='/tmp/output')
    print(f'Извлечено в: {extracted_path}')
Извлечено в: /tmp/output/image.jpg

Пример извлечения без сохранения метаданных:

import tarfile

with tarfile.open('archive.tar', 'r') as tar:
    tar.extract('data.json', set_attrs=False)
    print('Файл извлечен без атрибутов')
Файл извлечен без атрибутов

Пример использования numeric_owner:

import tarfile

with tarfile.open('archive.tar', 'r') as tar:
    tar.extract('script.sh', numeric_owner=True)
    print('Извлечение с числовыми идентификаторами владельца')
Извлечение с числовыми идентификаторами владельца

Похожие функции в Python

tarfile.TarFile.extractall() - извлекает все содержимое архива. Предпочтительнее при необходимости полной распаковки архива, а не отдельных элементов. Отличается поддержкой параметра members для фильтрации и параметра filter для безопасности.

shutil.unpack_archive() - универсальная функция для распаковки архивов различных форматов (tar, zip, gztar, bztar, xztar). Удобна при работе с разными типами архивов без необходимости явного указания формата. Не поддерживает тонкий контроль над отдельными файлами при распаковке.

zipfile.ZipFile.extract() - аналогичный метод для работы с ZIP-архивами. Используется при работе именно с форматом ZIP, имеет схожий интерфейс, но отличается внутренней реализацией и поддержкой специфичных для ZIP функций.

Аналоги функции в других языках

PHP: PharData::extractTo() - метод класса PharData для извлечения содержимого tar-архивов.

$phar = new PharData('archive.tar');
$phar->extractTo('/path/to/extract', 'file.txt', true);
echo 'Файл извлечен';
Файл извлечен

JavaScript (Node.js): модуль tar предоставляет потоковый API для работы с tar-архивами.

const tar = require('tar');
tar.x({
  file: 'archive.tar',
  C: '/path/to/extract'
}).then(() => console.log('Извлечение завершено'));
Извлечение завершено

Java: Apache Commons Compress предоставляет класс TarArchiveInputStream для последовательного чтения tar-архивов.

try (TarArchiveInputStream tis = new TarArchiveInputStream(
        new FileInputStream("archive.tar"))) {
    TarArchiveEntry entry;
    while ((entry = tis.getNextTarEntry()) != null) {
        if (entry.getName().equals("file.txt")) {
            Files.copy(tis, Paths.get("output/file.txt"));
            break;
        }
    }
    System.out.println("Файл извлечен");
}
Файл извлечен

Golang: пакет archive/tar предоставляет Reader для последовательного чтения архива.

file, _ := os.Open("archive.tar")
defer file.Close()
tr := tar.NewReader(file)
for {
    header, err := tr.Next()
    if err == io.EOF { break }
    if header.Name == "file.txt" {
        outFile, _ := os.Create("file.txt")
        io.Copy(outFile, tr)
        outFile.Close()
        fmt.Println("Файл извлечен")
        break
    }
}
Файл извлечен

Типичные ошибки при использовании

Ошибка при извлечении несуществующего файла:

import tarfile

try:
    with tarfile.open('archive.tar', 'r') as tar:
        tar.extract('missing_file.txt')
except KeyError as e:
    print(f'Ошибка: {e}')
Ошибка: "missing_file.txt"

Проблема с правами доступа при записи в целевой каталог:

import tarfile
import os

os.chmod('/protected_dir', 0o444)  # Только чтение
try:
    with tarfile.open('archive.tar', 'r') as tar:
        tar.extract('file.txt', path='/protected_dir')
except PermissionError as e:
    print(f'Ошибка прав доступа: {e}')
Ошибка прав доступа: [Errno 13] Permission denied

Ошибка при повреждении архива:

import tarfile

# Создаем битый архив
with open('corrupted.tar', 'wb') as f:
    f.write(b'invalid data')

try:
    with tarfile.open('corrupted.tar', 'r') as tar:
        tar.extract('any_file.txt')
except tarfile.ReadError as e:
    print(f'Ошибка чтения архива: {e}')
Ошибка чтения архива: file could not be opened successfully

Изменения в последних версиях Python

В Python 3.12 добавлен параметр filter для методов extract() и extractall(), позволяющий применять фильтры безопасности к извлекаемым путям. Это изменение направлено на предотвращение атак, связанных с извлечением файлов вне целевого каталога.

В Python 3.11 улучшена обработка символических ссылок в архивах, особенно на платформах Windows, где их поддержка была ограничена.

Начиная с Python 3.9, параметры set_attrs и numeric_owner стали доступны только как именованные аргументы при использовании после * в сигнатуре функции, что повышает читаемость кода.

Расширенные примеры использования

Извлечение файла с использованием объекта TarInfo:

Пример python
import tarfile

with tarfile.open('archive.tar', 'r') as tar:
    member_info = tar.getmember('data/config.yaml')
    # Модификация атрибутов перед извлечением
    member_info.mtime = 1609459200  # Установка времени модификации
    extracted_path = tar.extract(member_info, path='backup')
    print(f'Извлеченный путь: {extracted_path}')
Извлеченный путь: /full/path/backup/data/config.yaml

Извлечение с фильтрацией по префиксу имени:

Пример python
import tarfile
import os

with tarfile.open('project.tar.gz', 'r:gz') as tar:
    for member in tar.getmembers():
        if member.name.startswith('src/utils/'):
            # Создание директорий, если они отсутствуют
            os.makedirs(os.path.dirname(member.name), exist_ok=True)
            tar.extract(member)
            print(f'Извлечен: {member.name}')
Извлечен: src/utils/helpers.py
Извлечен: src/utils/constants.py

Извлечение с обработкой различных исключений:

Пример python
import tarfile
import traceback

def safe_extract(archive_path, member_name, extract_path):
    try:
        with tarfile.open(archive_path, 'r') as tar:
            return tar.extract(member_name, path=extract_path)
    except tarfile.TarError as e:
        print(f'Ошибка tar-архива: {e}')
        return None
    except OSError as e:
        print(f'Системная ошибка: {e}')
        return None
    except Exception as e:
        print(f'Неожиданная ошибка: {e}')
        traceback.print_exc()
        return None

result = safe_extract('data.tar', 'important.db', '/backup')
print(f'Результат: {result}')
Результат: /backup/important.db

Извлечение с ведением лога операций:

Пример python
import tarfile
import hashlib
from datetime import datetime

with tarfile.open('package.tar.xz', 'r:xz') as tar:
    member = tar.getmember('package/README.md')
    
    # Получение содержимого файла для вычисления хеша
    file_obj = tar.extractfile(member)
    content = file_obj.read()
    file_hash = hashlib.sha256(content).hexdigest()
    
    # Извлечение файла
    tar.extract(member, path='unpacked')
    
    # Логирование
    log_entry = f"{datetime.now()}: Извлечен {member.name}, " \
                f"размер: {member.size}, хеш: {file_hash[:16]}"
    print(log_entry)
2024-01-15 14:30:22.123456: Извлечен package/README.md, размер: 2048, хеш: a1b2c3d4e5f67890

питон tarfile.TarFile.extract function comments

En
Tarfile.TarFile.extract Extract file from TAR archive