How do I work with ZIP archives in Rust?

Walkthrough

The zip crate provides functionality to read and write ZIP archives in Rust. It supports various compression methods (Stored, Deflate, Bzip2, Zstd), handles file metadata, and allows for password-protected archives. You can create new ZIP files, extract existing ones, or modify archives in place. The crate streams data efficiently, making it suitable for both small and large archives. It's commonly used for backup systems, application packaging, and data exchange.

Key concepts:

  1. ZipWriter — creates new ZIP archives
  2. ZipArchive — reads existing ZIP archives
  3. Compression methods — Stored (no compression), Deflate, Bzip2, Zstd
  4. File options — compression method, permissions, timestamps
  5. Streaming — data is read/written incrementally, not loaded entirely into memory

Code Example

# Cargo.toml
[dependencies]
zip = "0.6"
use std::fs::File;
use std::io::prelude::*;
use zip::ZipWriter;
use zip::write::SimpleFileOptions;
 
fn main() -> std::io::Result<()> {
    let file = File::create("archive.zip")?;
    let mut zip = ZipWriter::new(file);
    
    let options = SimpleFileOptions::default().compression_method(zip::CompressionMethod::Stored);
    zip.start_file("hello.txt", options)?;
    zip.write_all(b"Hello, World!")?;
    
    zip.finish()?;
    Ok(())
}

Creating a ZIP Archive

use std::fs::File;
use std::io::prelude::*;
use std::io::{Read, Write};
use zip::ZipWriter;
use zip::write::SimpleFileOptions;
 
fn main() -> std::io::Result<()> {
    let file = File::create("example.zip")?;
    let mut zip = ZipWriter::new(file);
    
    // Use deflate compression
    let options = SimpleFileOptions::default()
        .compression_method(zip::CompressionMethod::Deflated);
    
    // Add a text file
    zip.start_file("readme.txt", options)?;
    zip.write_all(b"This is a readme file.\nIt contains documentation.")?;
    
    // Add another file
    zip.start_file("data/config.json", options)?;
    zip.write_all(b"{\"setting\": \"value\", \"enabled\": true}")?;
    
    // Add an uncompressed file
    zip.start_file("raw.txt", SimpleFileOptions::default())?;
    zip.write_all(b"This file is not compressed.")?;
    
    // Finish writing
    zip.finish()?;
    
    println!("Archive created successfully");
    Ok(())
}

Reading a ZIP Archive

use std::fs::File;
use zip::ZipArchive;
use std::io::prelude::*;
 
fn main() -> Result<(), Box<dyn std::error::Error>> {
    let file = File::open("example.zip")?;
    let mut archive = ZipArchive::new(file)?;
    
    // List files in archive
    println!("Files in archive:");
    for i in 0..archive.len() {
        let file = archive.by_index(i)?;
        println!("  {} ({} bytes)", file.name(), file.size());
    }
    
    // Read specific file by name
    let mut file = archive.by_name("readme.txt")?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    println!("\nContents of readme.txt:\n{}", contents);
    
    // Read file by index
    let mut file = archive.by_index(0)?;
    let mut buffer = Vec::new();
    file.read_to_end(&mut buffer)?;
    println!("\nFirst file has {} bytes", buffer.len());
    
    Ok(())
}

Compression Methods

use std::fs::File;
use std::io::prelude::*;
use zip::{ZipWriter, CompressionMethod};
use zip::write::SimpleFileOptions;
 
fn main() -> std::io::Result<()> {
    let file = File::create("compressed.zip")?;
    let mut zip = ZipWriter::new(file);
    
    // Stored - no compression
    zip.start_file("stored.txt", 
        SimpleFileOptions::default().compression_method(CompressionMethod::Stored))?;
    zip.write_all(b"This file has no compression.")?;
    
    // Deflate - standard compression
    zip.start_file("deflated.txt", 
        SimpleFileOptions::default().compression_method(CompressionMethod::Deflated))?;
    zip.write_all(b"This file uses deflate compression.")?;
    
    // Bzip2 - better compression, slower
    zip.start_file("bzip2.txt", 
        SimpleFileOptions::default().compression_method(CompressionMethod::Bzip2))?;
    zip.write_all(b"This file uses bzip2 compression.")?;
    
    // Zstd - modern compression
    zip.start_file("zstd.txt", 
        SimpleFileOptions::default().compression_method(CompressionMethod::Zstd))?;
    zip.write_all(b"This file uses zstd compression.")?;
    
    zip.finish()?;
    println!("Archive with various compression methods created");
    Ok(())
}

Extracting Files

use std::fs::{self, File};
use std::io::prelude::*;
use std::path::Path;
use zip::ZipArchive;
 
fn extract_all(archive_path: &str, dest_dir: &str) -> Result<(), Box<dyn std::error::Error>> {
    let file = File::open(archive_path)?;
    let mut archive = ZipArchive::new(file)?;
    
    // Create destination directory
    fs::create_dir_all(dest_dir)?;
    
    for i in 0..archive.len() {
        let mut file = archive.by_index(i)?;
        let file_name = file.mangled_name();
        let out_path = Path::new(dest_dir).join(file_name);
        
        if file.name().ends_with('/') {
            // It's a directory
            fs::create_dir_all(&out_path)?;
        } else {
            // It's a file
            if let Some(parent) = out_path.parent() {
                fs::create_dir_all(parent)?;
            }
            
            let mut out_file = File::create(&out_path)?;
            std::io::copy(&mut file, &mut out_file)?;
        }
    }
    
    println!("Extracted {} files to {}", archive.len(), dest_dir);
    Ok(())
}
 
fn main() -> Result<(), Box<dyn std::error::Error>> {
    // First create an archive for testing
    let file = File::create("test_archive.zip")?;
    let mut zip = zip::ZipWriter::new(file);
    let options = zip::write::SimpleFileOptions::default()
        .compression_method(zip::CompressionMethod::Deflated);
    
    zip.start_file("file1.txt", options)?;
    zip.write_all(b"Content of file 1")?;
    
    zip.start_file("subdir/file2.txt", options)?;
    zip.write_all(b"Content of file 2")?;
    
    zip.finish()?;
    
    // Now extract
    extract_all("test_archive.zip", "output")?;
    
    // Verify
    let content = fs::read_to_string("output/file1.txt")?;
    println!("Extracted content: {}", content);
    
    Ok(())
}

Adding Directories

use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
use walkdir::WalkDir;
use zip::ZipWriter;
use zip::write::SimpleFileOptions;
 
fn create_archive_from_directory(
    source_dir: &str,
    archive_path: &str,
) -> Result<(), Box<dyn std::error::Error>> {
    let file = File::create(archive_path)?;
    let mut zip = ZipWriter::new(file);
    let options = SimpleFileOptions::default()
        .compression_method(zip::CompressionMethod::Deflated);
    
    let source_path = Path::new(source_dir);
    
    for entry in WalkDir::new(source_dir) {
        let entry = entry?;
        let path = entry.path();
        
        // Skip the root directory itself
        if path == source_path {
            continue;
        }
        
        // Get relative path
        let relative = path.strip_prefix(source_path)?;
        let archive_name = relative.to_string_lossy();
        
        if path.is_dir() {
            // Add directory entry (ends with /)
            zip.add_directory(&format!("{}/", archive_name), options)?;
        } else {
            // Add file
            zip.start_file(&archive_name, options)?;
            let mut file = File::open(path)?;
            std::io::copy(&mut file, &mut zip)?;
        }
    }
    
    zip.finish()?;
    println!("Archive created from {}", source_dir);
    Ok(())
}
 
fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create test directory
    std::fs::create_dir_all("test_dir/subdir")?;
    std::fs::write("test_dir/file1.txt", b"Content 1")?;
    std::fs::write("test_dir/subdir/file2.txt", b"Content 2")?;
    
    create_archive_from_directory("test_dir", "directory.zip")?;
    
    // Cleanup
    std::fs::remove_dir_all("test_dir")?;
    Ok(())
}

Password-Protected Archives

use std::fs::File;
use std::io::prelude::*;
use zip::{ZipWriter, ZipArchive};
use zip::write::SimpleFileOptions;
use zip::read::ZipFile;
 
fn create_encrypted_archive(path: &str, password: &str) -> std::io::Result<()> {
    let file = File::create(path)?;
    let mut zip = ZipWriter::new(file);
    
    let options = SimpleFileOptions::default()
        .compression_method(zip::CompressionMethod::Deflated)
        .with_deprecated_encryption(password.as_bytes());
    
    zip.start_file("secret.txt", options)?;
    zip.write_all(b"This content is encrypted.")?;
    
    zip.finish()?;
    println!("Encrypted archive created");
    Ok(())
}
 
fn read_encrypted_archive(path: &str, password: &str) -> Result<String, Box<dyn std::error::Error>> {
    let file = File::open(path)?;
    let mut archive = ZipArchive::new(file)?;
    
    let mut encrypted_file = archive.by_name_decrypt("secret.txt", password.as_bytes())?;
    
    let mut contents = String::new();
    encrypted_file.read_to_string(&mut contents)?;
    
    Ok(contents)
}
 
fn main() -> Result<(), Box<dyn std::error::Error>> {
    create_encrypted_archive("secret.zip", "mypassword")?;
    let contents = read_encrypted_archive("secret.zip", "mypassword")?;
    println!("Decrypted: {}", contents);
    
    // Note: AES encryption requires the `aes-crypto` feature
    Ok(())
}

File Metadata and Timestamps

use std::fs::File;
use std::io::prelude::*;
use zip::{ZipWriter, ZipArchive};
use zip::write::SimpleFileOptions;
 
fn main() -> Result<(), Box<dyn std::error::Error>> {
    let file = File::create("metadata.zip")?;
    let mut zip = ZipWriter::new(file);
    
    // Create file with metadata
    let options = SimpleFileOptions::default()
        .compression_method(zip::CompressionMethod::Deflated)
        .unix_permissions(0o644); // rw-r--r--
    
    zip.start_file("document.txt", options)?;
    zip.write_all(b"File with metadata")?;
    
    zip.finish()?;
    
    // Read metadata
    let file = File::open("metadata.zip")?;
    let archive = ZipArchive::new(file)?;
    
    println!("Archive contains {} files", archive.len());
    
    for i in 0..archive.len() {
        let file = archive.by_index(i)?;
        println!("\nFile: {}", file.name());
        println!("  Compressed size: {}", file.compressed_size());
        println!("  Original size: {}", file.size());
        println!("  Compression: {:?}", file.compression());
        println!("  Modified: {:?}", file.last_modified());
        println!("  Is directory: {}", file.is_dir());
        println!("  Is file: {}", file.is_file());
    }
    
    Ok(())
}

Streaming Large Files

use std::fs::File;
use std::io::{self, Read, Write};
use zip::{ZipWriter, ZipArchive};
use zip::write::SimpleFileOptions;
 
fn create_large_archive() -> io::Result<()> {
    let file = File::create("large.zip")?;
    let mut zip = ZipWriter::new(file);
    let options = SimpleFileOptions::default()
        .compression_method(zip::CompressionMethod::Deflated);
    
    // Stream a large file into the archive
    zip.start_file("large_file.bin", options)?;
    
    // Write in chunks to avoid loading everything into memory
    let chunk_size = 1024 * 1024; // 1MB chunks
    for i in 0..10 {
        let chunk = vec![i as u8; chunk_size];
        zip.write_all(&chunk)?;
    }
    
    zip.finish()?;
    println!("Large archive created");
    Ok(())
}
 
fn read_large_archive() -> io::Result<()> {
    let file = File::open("large.zip")?;
    let mut archive = ZipArchive::new(file)?;
    
    let mut file = archive.by_name("large_file.bin")?;
    
    // Read in chunks
    let mut buffer = [0u8; 4096];
    let mut total = 0;
    
    loop {
        let bytes_read = file.read(&mut buffer)?;
        if bytes_read == 0 {
            break;
        }
        total += bytes_read;
    }
    
    println!("Read {} bytes", total);
    Ok(())
}
 
fn main() -> io::Result<()> {
    create_large_archive()?;
    read_large_archive()
}

Appending to Existing Archives

use std::fs::File;
use std::io::prelude::*;
use std::fs::OpenOptions;
use zip::{ZipWriter, ZipArchive};
use zip::write::SimpleFileOptions;
 
fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create initial archive
    {
        let file = File::create("append.zip")?;
        let mut zip = ZipWriter::new(file);
        let options = SimpleFileOptions::default();
        
        zip.start_file("original.txt", options)?;
        zip.write_all(b"Original content")?;
        zip.finish()?;
    }
    
    // Read existing archive
    let existing_file = File::open("append.zip")?;
    let archive = ZipArchive::new(existing_file)?;
    
    // Note: To truly append, you need to copy existing entries
    // Here's a simpler approach: create new archive with old + new content
    
    let new_file = File::create("append_new.zip")?;
    let mut new_zip = ZipWriter::new(new_file);
    let options = SimpleFileOptions::default();
    
    // Copy old entries
    let old_archive = ZipArchive::new(File::open("append.zip")?)?;
    for i in 0..old_archive.len() {
        let mut old_file = old_archive.by_index(i)?;
        new_zip.start_file(old_file.name(), options)?;
        std::io::copy(&mut old_file, &mut new_zip)?;
    }
    
    // Add new entry
    new_zip.start_file("added.txt", options)?;
    new_zip.write_all(b"Added later")?;
    
    new_zip.finish()?;
    
    // Replace old file
    std::fs::rename("append_new.zip", "append.zip")?;
    println!("Archive updated");
    
    Ok(())
}

Handling Symlinks

use std::fs::File;
use std::io::prelude::*;
use zip::{ZipWriter, ZipArchive};
use zip::write::SimpleFileOptions;
 
#[cfg(unix)]
fn main() -> Result<(), Box<dyn std::error::Error>> {
    let file = File::create("symlinks.zip")?;
    let mut zip = ZipWriter::new(file);
    let options = SimpleFileOptions::default();
    
    // Add a regular file
    zip.start_file("original.txt", options)?;
    zip.write_all(b"Original content")?;
    
    // Add a symlink entry (on Unix)
    #[cfg(unix)]
    {
        let symlink_options = SimpleFileOptions::default()
            .unix_permissions(0o120777); // Symlink permissions
        zip.start_file("link_to_original.txt", symlink_options)?;
        // The symlink target is stored as the file content
        zip.write_all(b"original.txt")?;
    }
    
    zip.finish()?;
    println!("Archive with symlink created");
    
    Ok(())
}

Real-World: Backup System

use std::fs::File;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::time::SystemTime;
use zip::{ZipWriter, ZipArchive};
use zip::write::SimpleFileOptions;
 
struct Backup {
    archive_path: PathBuf,
}
 
impl Backup {
    fn new<P: AsRef<Path>>(path: P) -> Self {
        Self { archive_path: path.as_ref().to_path_buf() }
    }
    
    fn create(&self, source_dir: &Path) -> Result<(), Box<dyn std::error::Error>> {
        let file = File::create(&self.archive_path)?;
        let mut zip = ZipWriter::new(file);
        let options = SimpleFileOptions::default()
            .compression_method(zip::CompressionMethod::Deflated);
        
        self.add_directory(source_dir, source_dir, &mut zip, options)?;
        
        zip.finish()?;
        println!("Backup created: {}", self.archive_path.display());
        Ok(())
    }
    
    fn add_directory<W: std::io::Write>(
        &self,
        dir: &Path,
        base: &Path,
        zip: &mut ZipWriter<W>,
        options: SimpleFileOptions,
    ) -> Result<(), Box<dyn std::error::Error>> {
        for entry in std::fs::read_dir(dir)? {
            let entry = entry?;
            let path = entry.path();
            let relative = path.strip_prefix(base)?;
            
            if path.is_dir() {
                self.add_directory(&path, base, zip, options)?;
            } else {
                zip.start_file(relative.to_string_lossy(), options)?;
                let mut file = File::open(&path)?;
                std::io::copy(&mut file, zip)?;
            }
        }
        Ok(())
    }
    
    fn restore(&self, dest_dir: &Path) -> Result<(), Box<dyn std::error::Error>> {
        std::fs::create_dir_all(dest_dir)?;
        
        let file = File::open(&self.archive_path)?;
        let mut archive = ZipArchive::new(file)?;
        
        for i in 0..archive.len() {
            let mut file = archive.by_index(i)?;
            let out_path = dest_dir.join(file.mangled_name());
            
            if file.name().ends_with('/') {
                std::fs::create_dir_all(&out_path)?;
            } else {
                if let Some(parent) = out_path.parent() {
                    std::fs::create_dir_all(parent)?;
                }
                let mut out_file = File::create(&out_path)?;
                std::io::copy(&mut file, &mut out_file)?;
            }
        }
        
        println!("Backup restored to {}", dest_dir.display());
        Ok(())
    }
    
    fn list(&self) -> Result<Vec<String>, Box<dyn std::error::Error>> {
        let file = File::open(&self.archive_path)?;
        let archive = ZipArchive::new(file)?;
        
        let mut files = Vec::new();
        for i in 0..archive.len() {
            let file = archive.by_index(i)?;
            files.push(format!("{} ({} bytes)", file.name(), file.size()));
        }
        Ok(files)
    }
}
 
fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create test data
    std::fs::create_dir_all("backup_source/subdir")?;
    std::fs::write("backup_source/file1.txt", b"File 1 content")?;
    std::fs::write("backup_source/subdir/file2.txt", b"File 2 content")?;
    
    // Create backup
    let backup = Backup::new("backup.zip");
    backup.create(Path::new("backup_source"))?;
    
    // List contents
    println!("\nBackup contents:");
    for file in backup.list()? {
        println!("  {}", file);
    }
    
    // Restore
    backup.restore(Path::new("backup_restore"))?;
    
    // Cleanup
    std::fs::remove_dir_all("backup_source")?;
    std::fs::remove_dir_all("backup_restore")?;
    std::fs::remove_file("backup.zip")?;
    
    Ok(())
}

Real-World: Configuration Archive

use std::fs::File;
use std::io::prelude::*;
use std::collections::HashMap;
use zip::{ZipWriter, ZipArchive};
use zip::write::SimpleFileOptions;
 
pub struct ConfigArchive {
    configs: HashMap<String, String>,
}
 
impl ConfigArchive {
    pub fn new() -> Self {
        Self { configs: HashMap::new() }
    }
    
    pub fn set(&mut self, key: &str, value: &str) {
        self.configs.insert(key.to_string(), value.to_string());
    }
    
    pub fn get(&self, key: &str) -> Option<&String> {
        self.configs.get(key)
    }
    
    pub fn save(&self, path: &str) -> std::io::Result<()> {
        let file = File::create(path)?;
        let mut zip = ZipWriter::new(file);
        let options = SimpleFileOptions::default()
            .compression_method(zip::CompressionMethod::Deflated);
        
        for (name, content) in &self.configs {
            let file_name = format!("configs/{}.json", name);
            zip.start_file(&file_name, options)?;
            zip.write_all(content.as_bytes())?;
        }
        
        zip.finish()?;
        Ok(())
    }
    
    pub fn load(&mut self, path: &str) -> Result<(), Box<dyn std::error::Error>> {
        let file = File::open(path)?;
        let mut archive = ZipArchive::new(file)?;
        
        for i in 0..archive.len() {
            let mut file = archive.by_index(i)?;
            let name = file.name().to_string();
            
            if name.starts_with("configs/") && name.ends_with(".json") {
                let key = name
                    .strip_prefix("configs/")
                    .unwrap()
                    .strip_suffix(".json")
                    .unwrap();
                
                let mut content = String::new();
                file.read_to_string(&mut content)?;
                self.configs.insert(key.to_string(), content);
            }
        }
        
        Ok(())
    }
    
    pub fn list(&self) -> Vec<&String> {
        self.configs.keys().collect()
    }
}
 
fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut config = ConfigArchive::new();
    
    config.set("database", r"{\"host\": \"localhost\", \"port\": 5432}");
    config.set("app", r"{\"name\": \"MyApp\", \"version\": \"1.0\"}");
    
    config.save("configs.zip")?;
    println!("Saved {} configs", config.list().len());
    
    // Load into new instance
    let mut loaded = ConfigArchive::new();
    loaded.load("configs.zip")?;
    
    println!("Loaded configs:");
    for key in loaded.list() {
        println!("  {}: {}", key, loaded.get(key).unwrap());
    }
    
    std::fs::remove_file("configs.zip")?;
    Ok(())
}

Real-World: Self-Extracting Archive

use std::fs::File;
use std::io::prelude::*;
use zip::{ZipWriter, ZipArchive};
use zip::write::SimpleFileOptions;
 
fn create_self_extracting_archive(
    source_path: &str,
    output_path: &str,
) -> std::io::Result<()> {
    let file = File::create(output_path)?;
    let mut zip = ZipWriter::new(file);
    let options = SimpleFileOptions::default()
        .compression_method(zip::CompressionMethod::Deflated);
    
    // Add files
    zip.start_file("data/file1.txt", options)?;
    zip.write_all(b"Content 1")?;
    
    zip.start_file("data/file2.txt", options)?;
    zip.write_all(b"Content 2")?;
    
    // Add extract script (for shell)
    zip.start_file("extract.sh", options.clone())?;
    let script = r"#!/bin/bash
# Self-extracting archive extraction script
# The ZIP data follows this script
 
SCRIPT_LEN=$(wc -l < "$0")
ARCHIVE="$(dirname "$0")/archive.zip"
 
# Extract the ZIP portion
tail -n +$((SCRIPT_LEN + 1)) "$0" > "$ARCHIVE"
 
# Unzip
unzip -o "$ARCHIVE" -d "extracted"
rm "$ARCHIVE"
 
exit 0
";
    zip.write_all(script.as_bytes())?;
    
    zip.finish()?;
    println!("Self-extracting archive created: {}", output_path);
    Ok(())
}
 
fn main() -> std::io::Result<()> {
    create_self_extracting_archive("input", "extract.sh")?;
    println!("Run 'bash extract.sh' to extract");
    Ok(())
}

Error Handling

use std::fs::File;
use zip::ZipArchive;
use zip::result::ZipError;
 
fn main() {
    match read_zip_contents("nonexistent.zip") {
        Ok(contents) => println!("Contents: {}", contents),
        Err(ZipError::Io(io_err)) => eprintln!("IO error: {}", io_err),
        Err(ZipError::InvalidArchive(msg)) => eprintln!("Invalid archive: {}", msg),
        Err(ZipError::UnsupportedArchive(msg)) => eprintln!("Unsupported: {}", msg),
        Err(other) => eprintln!("Error: {}", other),
    }
}
 
fn read_zip_contents(path: &str) -> Result<String, ZipError> {
    let file = File::open(path)?;
    let mut archive = ZipArchive::new(file)?;
    
    let mut file = archive.by_name("missing_file.txt")?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    
    Ok(contents)
}

Checking Archive Integrity

use std::fs::File;
use zip::ZipArchive;
 
fn verify_archive(path: &str) -> Result<bool, Box<dyn std::error::Error>> {
    let file = File::open(path)?;
    let archive = ZipArchive::new(file)?;
    
    println!("Archive: {}", path);
    println!("Contains {} files", archive.len());
    
    let mut total_compressed = 0;
    let mut total_original = 0;
    
    for i in 0..archive.len() {
        let file = archive.by_index(i)?;
        println!("  {}", file.name());
        println!("    Compressed: {} bytes", file.compressed_size());
        println!("    Original: {} bytes", file.size());
        println!("    Method: {:?}", file.compression());
        
        total_compressed += file.compressed_size();
        total_original += file.size();
    }
    
    if total_original > 0 {
        let ratio = 100.0 * (1.0 - (total_compressed as f64 / total_original as f64));
        println!("\nCompression ratio: {:.1}%", ratio);
    }
    
    Ok(true)
}
 
fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create test archive
    let file = File::create("verify.zip")?;
    let mut zip = zip::ZipWriter::new(file);
    let options = zip::write::SimpleFileOptions::default()
        .compression_method(zip::CompressionMethod::Deflated);
    
    zip.start_file("file1.txt", options)?;
    zip.write_all(b"AAAAAAAAAAAAAAAAAAAAAAAA")?; // Highly compressible
    
    zip.start_file("file2.txt", options)?;
    zip.write_all(b"BBBBBBBBBBBBBBBBBBBBBBBB")?;
    
    zip.finish()?;
    
    // Verify
    verify_archive("verify.zip")?;
    
    std::fs::remove_file("verify.zip")?;
    Ok(())
}

Summary

  • ZipWriter::new(file) creates a new ZIP archive
  • ZipArchive::new(file) opens an existing archive
  • zip.start_file(name, options) begins writing a file entry
  • CompressionMethod::Deflated is standard compression
  • CompressionMethod::Stored stores without compression
  • archive.by_name(name) retrieves a file by name
  • archive.by_index(i) retrieves a file by index
  • Use .with_deprecated_encryption(password) for password protection
  • .unix_permissions(mode) sets file permissions
  • Iterate with archive.len() and by_index(i)
  • Stream large files to avoid memory issues
  • Handle errors with ZipError enum
  • Great for backup systems, configuration archives, and data exchange