Работа с ZIP-архивами в Rust: библиотека zip для создания и распаковки архивов

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Библиотека zip для работы с архивами на Rust

В современной разработке на Rust часто возникает необходимость упаковывать данные в ZIP-архивы или извлекать их оттуда. Будь то создание резервных копий, распространение программного обеспечения или обработка пользовательских файлов — библиотека zip является стандартным решением для этой задачи. Она предоставляет удобный API для чтения, записи и модификации ZIP-архивов, поддерживая как потоковую обработку, так и работу в памяти.

Установка и подключение

Для начала работы добавьте зависимость в ваш Cargo.toml:

[dependencies]
zip = "2.1"

Также может потребоваться крейт std::io для работы с потоками данных, который уже входит в стандартную библиотеку Rust.

Создание нового ZIP-архива

Рассмотрим простейший пример — создание архива с одним текстовым файлом. Для этого используется ZipWriter, который оборачивает любой тип, реализующий Write:

use std::fs::File;
use std::io::Write;
use zip::write::FileOptions;
use zip::ZipWriter;

fn main() -> zip::result::ZipResult<()> {
    let file = File::create("example.zip")?;
    let mut zip = ZipWriter::new(file);

    zip.start_file("hello.txt", FileOptions::default())?;
    zip.write_all(b"Hello, Rust ZIP!")?;

    zip.finish()?;
    Ok(())
}

Обратите внимание на метод start_file — он начинает запись нового файла внутри архива. Вы можете передать ему опции сжатия, дату модификации и другие параметры.

Чтение и извлечение файлов

Для чтения архива используется ZipArchive. Он позволяет перебирать все записи и извлекать их содержимое:

use std::fs::File;
use std::io::Read;
use zip::ZipArchive;

fn main() -> zip::result::ZipResult<()> {
    let file = File::open("example.zip")?;
    let mut archive = ZipArchive::new(file)?;

    for i in 0..archive.len() {
        let mut entry = archive.by_index(i)?;
        let name = entry.name().to_string();
        let mut content = String::new();
        entry.read_to_string(&mut content)?;
        println!("{}: {}", name, content);
    }
    Ok(())
}

Метод by_index возвращает конкретную запись по индексу. Также доступен поиск по имени через by_name, но имейте в виду — имена в ZIP могут быть в разных кодировках.

Добавление файлов в существующий архив

Библиотека zip также поддерживает добавление новых файлов в уже созданный архив. Это делается с помощью метода raw_copy_file или путём открытия архива в режиме добавления:

use std::fs::File;
use std::io::Write;
use zip::write::FileOptions;
use zip::ZipWriter;

fn append_to_zip() -> zip::result::ZipResult<()> {
    let file = File::options()
        .read(true)
        .write(true)
        .open("example.zip")?;
    let mut zip = ZipWriter::new_append(file)?;

    zip.start_file("new_file.txt", FileOptions::default())?;
    zip.write_all(b"Added later!")?;

    zip.finish()?;
    Ok(())
}

Важно: для добавления файла архив должен быть открыт с правами на чтение и запись, а сам файл не должен быть повреждён.

Работа с разными типами сжатия

По умолчанию библиотека использует метод Deflated (стандартное сжатие ZIP). Вы можете изменить его на Stored (без сжатия) или другие методы, передав соответствующие опции:

use zip::CompressionMethod;
use zip::write::FileOptions;

let options = FileOptions::default()
    .compression_method(CompressionMethod::Stored);
// или
let options = FileOptions::default()
    .compression_method(CompressionMethod::Deflated);

Если вам нужно максимальное сжатие, укажите уровень:

let options = FileOptions::default()
    .compression_method(CompressionMethod::Deflated)
    .unix_permissions(0o755);

Обработка ошибок и лучшие практики

Библиотека использует собственный тип ошибок zip::result::ZipError, который реализует std::error::Error. Рекомендуется обрабатывать ошибки с помощью оператора ? или оборачивать их в свои типы. Вот несколько советов:

  • Всегда вызывайте finish() для ZipWriter, чтобы корректно завершить архив.
  • При чтении больших

Рекомендаций