Working with ZIP Archives in Rust Using the zip Library
When developing in Rust, there is often a need to package files into ZIP archives or extract data from them. This may be required for distributing software, creating backups, processing user-uploaded archives, or building packages. The Rust standard library does not include built-in tools for working with ZIP, but the ecosystem offers a powerful and convenient library called zip.
In this article, we will thoroughly examine how to use the zip library for creating, reading, and extracting ZIP archives. You will learn how to install the library, work with files and directories, handle errors, and manage compression.
Installing the zip Library
To begin, add the dependency to your project's Cargo.toml file:
[dependencies]zip = "2.2"The library is actively maintained and uses modern Rust features. After adding the dependency, you can import it into your code:
use zip::ZipWriter;use zip::read::ZipArchive;use std::io::{Read, Write, BufWriter, BufReader};use std::fs::{self, File};Creating a ZIP Archive
Creating an archive consists of several steps: opening a file for writing, initializing a ZipWriter, adding files, and finalizing the write. Consider an example that packages a single text file:
use std::fs::File;use zip::ZipWriter;use zip::write::FileOptions;use std::io::Write;
fn create_archive() -> zip::result::ZipResult<()> { let file = File::create("example.zip")?; let mut zip = ZipWriter::new(file);
let options = FileOptions::default() .compression_method(zip::CompressionMethod::Deflated) .unix_permissions(0o755);
zip.start_file("hello.txt", options)?; zip.write_all(b"Hello, Rust ZIP!")?;
zip.finish()?; Ok(())}Here we:
- Create the file
example.zipin the current directory. - Initialize a
ZipWriter. - Configure file parameters: the
Deflatedcompression method (standard compression) and permissions. - Add the file
hello.txtand write content to it. - Finalize the write by calling
finish().
To add multiple files or an entire directory, use a loop over the files in the folder:
fn add_directory(zip: &mut ZipWriter<File>, dir_path: &str) -> zip::result::ZipResult<()> { for entry in walkdir::WalkDir::new(dir_path) { let entry = entry?; let path = entry.path(); if path.is_file() { let name = path.strip_prefix(dir_path).unwrap().to_str().unwrap(); zip.start_file(name, FileOptions::default())?; let mut f = File::open(path)?; std::io::copy(&mut f, zip)?; } } Ok(())}Note: for recursive directory traversal, it is convenient to use the walkdir crate, but it needs to be added separately.
Reading and Extracting a ZIP Archive
To read an archive, use ZipArchive. Below is an example that lists the files in the archive and extracts them to a specified folder:
use zip::ZipArchive;use std::io::Read;
fn extract_archive(archive_path: &str, output_dir: &str) -> zip::result::ZipResult<()> { let file = File::open(archive_path)?; let mut archive = ZipArchive::new(file)?;
for i in 0..archive.len() { let mut entry = archive.by_index(i)?; let entry_name = entry.name().to_string(); println!("Extracting: {}", entry_name);
// Create the full path to the file let output_path = format!("{}/{}", output_dir, entry_nam