Библиотека 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, чтобы корректно завершить архив. - При чтении больших