Zipfile.ZipFile.extract: примеры (PYTHON)

Метод extract в Python: извлечение файлов из ZIP-архивов
Раздел: Архивы, Распаковка
zipfile.ZipFile.extract(member, path, pwd): str

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

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

Сигнатура метода: ZipFile.extract(member, path=None, pwd=None)

Аргументы:

  • member (обязательный) – определяет файл для извлечения. Может быть строкой с именем файла в архиве или объектом ZipInfo.
  • path (опциональный) – путь к целевой директории для извлечения. По умолчанию используется текущая рабочая директория (None). Если указанный путь не существует, он будет создан.
  • pwd (опциональный) – байтовая строка с паролем для расшифровки зашифрованных файлов. Для архивов, созданных в старых версиях Python, может потребоваться строковый тип.

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

Метод выполняет проверки на безопасность, предотвращая атаки типа "Zip Slip", которые пытаются записать файлы за пределами целевой директории.

Краткие примеры использования

Пример 1: Базовое извлечение файла.

import zipfile

with zipfile.ZipFile('archive.zip', 'r') as zf:
    extracted_path = zf.extract('document.txt')
    print(extracted_path)
C:\Projects\document.txt

Пример 2: Извлечение файла в указанную директорию.

import zipfile

with zipfile.ZipFile('archive.zip', 'r') as zf:
    extracted_path = zf.extract('image.jpg', path='output/images')
    print(extracted_path)
C:\Projects\output\images\image.jpg

Пример 3: Использование пароля для зашифрованного архива.

import zipfile

with zipfile.ZipFile('encrypted.zip', 'r') as zf:
    extracted_path = zf.extract('secret.txt', pwd=b'my_password')
    print(extracted_path)
C:\Projects\secret.txt

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

1. ZipFile.extractall() – извлекает все файлы из архива сразу. Предпочтительнее использовать, когда требуется полная распаковка всего содержимого архива. Метод extract более эффективен для выборочного извлечения.

2. ZipFile.read() – читает содержимое файла из архива и возвращает его в виде байтовой строки, не создавая файлов на диске. Удобен для обработки данных непосредственно в памяти, например, для парсинга CSV или JSON из архива.

3. shutil.unpack_archive() – высокоуровневая функция для распаковки различных форматов архивов (ZIP, TAR, GZTAR и др.). Подходит для простых сценариев, где не требуется тонкого контроля над процессом извлечения.

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

Java (java.util.zip.ZipFile): требует более многословного кода, работа ведется через потоки ввода-вывода.

import java.util.zip.ZipFile;
import java.io.*;

public class Main {
    public static void main(String[] args) throws IOException {
        ZipFile zipFile = new ZipFile("archive.zip");
        zipFile.stream().forEach(entry -> {
            try {
                InputStream is = zipFile.getInputStream(entry);
                Files.copy(is, Paths.get("output/" + entry.getName()));
            } catch (IOException e) { e.printStackTrace(); }
        });
        zipFile.close();
    }
}

JavaScript (Node.js, библиотека adm-zip): работа с архивами через сторонние библиотеки.

const AdmZip = require('adm-zip');
const zip = new AdmZip('archive.zip');
zip.extractEntryTo('document.txt', './output', false, true);

PHP (ZipArchive): интерфейс, похожий на Python, но с использованием префикса методов.

$zip = new ZipArchive;
if ($zip->open('archive.zip') === TRUE) {
    $zip->extractTo('./output', ['document.txt']);
    $zip->close();
}

C# (System.IO.Compression.ZipFileExtensions): метод ExtractToFile в пространстве имен System.IO.Compression.

using System.IO.Compression;

using (ZipArchive archive = ZipFile.OpenRead("archive.zip"))
{
    archive.GetEntry("document.txt").ExtractToFile("./output/document.txt");
}

Основное отличие Python-реализации заключается в использовании контекстного менеджера (with) для автоматического управления ресурсами и более лаконичном синтаксисе.

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

1. KeyError при отсутствии файла в архиве.

import zipfile

try:
    with zipfile.ZipFile('archive.zip', 'r') as zf:
        zf.extract('missing_file.txt')
except KeyError as e:
    print(f"Файл не найден в архиве: {e}")
Файл не найден в архиве: 'missing_file.txt'

2. RuntimeError при неверном пароле для зашифрованного архива.

import zipfile

try:
    with zipfile.ZipFile('encrypted.zip', 'r') as zf:
        zf.extract('file.txt', pwd=b'wrong_password')
except RuntimeError as e:
    print(f"Ошибка распаковки: {e}")
Ошибка распаковки: Bad password for file 'file.txt'

3. FileNotFoundError при отсутствии архива.

import zipfile

try:
    with zipfile.ZipFile('nonexistent.zip', 'r') as zf:
        zf.extract('file.txt')
except FileNotFoundError as e:
    print(f"Архив не найден: {e}")
Архив не найден: [Errno 2] No such file or directory: 'nonexistent.zip'

4. ValueError при попытке извлечения файла с помощью объекта ZipInfo, не принадлежащего текущему архиву.

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

В Python 3.11 в модуль zipfile было добавлено улучшение, касающееся работы с паролями. В более ранних версиях, при использовании метода extract() с неверным паролем, возникало общее исключение RuntimeError. В Python 3.11 добавлена более конкретная ошибка zipfile.BadZipFile с уточняющим сообщением для случаев неверного пароля.

В Python 3.6 были улучшены механизмы безопасности, предотвращающие атаки типа Zip Slip. Метод extract() стал более строго проверять пути извлечения файлов.

С Python 3.4 метод extract() и другие методы класса ZipFile стали возвращать путь в кодировке файловой системы, что улучшило обработку путей с не-ASCII символами на Windows.

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

Пример 1: Извлечение файла с использованием объекта ZipInfo. Это может быть полезно при работе с метаданными файлов в архиве.

Пример python
import zipfile
import os

with zipfile.ZipFile('archive.zip', 'r') as zf:
    # Получаем объект ZipInfo для файла
    file_info = zf.getinfo('data.csv')
    print(f"Имя файла: {file_info.filename}")
    print(f"Размер сжатого файла: {file_info.compress_size} байт")
    print(f"Исходный размер: {file_info.file_size} байт")
    
    # Извлекаем с использованием объекта ZipInfo
    extracted_path = zf.extract(file_info, path='extracted_data')
    print(f"Извлечен в: {extracted_path}")
Имя файла: data.csv
Размер сжатого файла: 1024 байт
Исходный размер: 2048 байт
Извлечен в: C:\Projects\extracted_data\data.csv

Пример 2: Извлечение файла с переименованием в целевой директории. Метод extract не поддерживает прямое переименование, поэтому можно использовать комбинацию с os.rename.

Пример python
import zipfile
import os

with zipfile.ZipFile('archive.zip', 'r') as zf:
    # Извлекаем файл во временное расположение
    temp_path = zf.extract('old_name.txt', path='temp')
    
    # Переименовываем извлеченный файл
    new_path = os.path.join('temp', 'new_name.txt')
    os.rename(temp_path, new_path)
    
    print(f"Файл переименован: {new_path}")
Файл переименован: temp/new_name.txt

Пример 3: Безопасное извлечение файлов с проверкой пути. Демонстрация встроенной защиты от Zip Slip атак.

Пример python
import zipfile

# Создаем архив с потенциально опасным именем файла
with zipfile.ZipFile('malicious.zip', 'w') as zf:
    zf.writestr('../../dangerous.txt', 'harmful content')

# Попытка извлечения опасного файла
with zipfile.ZipFile('malicious.zip', 'r') as zf:
    try:
        zf.extract('../../dangerous.txt')
    except Exception as e:
        print(f"Безопасность: {type(e).__name__}: {e}")
Безопасность: ValueError: '../../dangerous.txt' является абсолютным или выходит за пределы целевого каталога

Пример 4: Извлечение файлов из вложенных директорий архива. Метод extract корректно обрабатывает пути с поддиректориями.

Пример python
import zipfile
import os

# Создаем архив с вложенной структурой
with zipfile.ZipFile('nested.zip', 'w') as zf:
    zf.writestr('folder/subfolder/file.txt', 'Содержимое файла')

# Извлекаем файл из вложенной директории
with zipfile.ZipFile('nested.zip', 'r') as zf:
    extracted_path = zf.extract('folder/subfolder/file.txt', path='output')
    
    # Проверяем существование файла
    if os.path.exists(extracted_path):
        print(f"Файл успешно извлечен: {extracted_path}")
        # Проверяем, что структура каталогов создана
        print("Существует ли директория 'output/folder/subfolder':", 
              os.path.exists('output/folder/subfolder'))
Файл успешно извлечен: output/folder/subfolder/file.txt
Существует ли директория 'output/folder/subfolder': True

Пример 5: Пакетное извлечение нескольких файлов по условию. Извлечение только файлов с определенным расширением.

Пример python
import zipfile

with zipfile.ZipFile('project.zip', 'r') as zf:
    # Получаем список всех файлов в архиве
    all_files = zf.namelist()
    
    # Фильтруем только Python файлы
    python_files = [f for f in all_files if f.endswith('.py')]
    
    # Извлекаем каждый Python файл
    for py_file in python_files:
        extracted_path = zf.extract(py_file, path='python_code')
        print(f"Извлечен: {py_file} -> {extracted_path}")
Извлечен: main.py -> python_code/main.py
Извлечен: utils/helpers.py -> python_code/utils/helpers.py

питон zipfile.ZipFile.extract function comments

En
Zipfile.ZipFile.extract Extract file from ZIP archive