Loading page…
Rust walkthroughs
Loading page…
The zip crate provides support for reading and writing ZIP archives. It handles the ZIP file format including compression, decompression, and various archive features like password protection. You can create new ZIP files, extract files from existing archives, list archive contents, modify archives, and work with different compression methods. The crate supports stored (uncompressed), Deflate, Bzip2, and other compression algorithms.
Key concepts:
# Cargo.toml
[dependencies]
zip = "2"use std::fs::File;
use std::io::prelude::*;
use zip::write::FileOptions;
use zip::CompressionMethod;
use zip::ZipWriter;
fn main() -> std::io::Result<()> {
// Create a new ZIP file
let file = File::create("archive.zip")?;
let mut zip = ZipWriter::new(file);
let options = FileOptions::default()
.compression_method(CompressionMethod::Deflated);
// Add a file
zip.start_file("hello.txt", options)?;
zip.write_all(b"Hello, World!")?;
// Finish and save
zip.finish()?;
println!("Created archive.zip");
Ok(())
}use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
use zip::write::FileOptions;
use zip::{ZipWriter, CompressionMethod};
fn create_zip(output_path: &str, files: &[(&str, &[u8])]) -> std::io::Result<()> {
let file = File::create(output_path)?;
let mut zip = ZipWriter::new(file);
let options = FileOptions::default()
.compression_method(CompressionMethod::Deflated);
for (name, data) in files {
zip.start_file(*name, options)?;
zip.write_all(data)?;
}
zip.finish()?;
Ok(())
}
fn main() -> std::io::Result<()> {
let files = vec![
("readme.txt", b"This is a README file." as &[u8]),
("data/config.json", b"{\"name\": \"example\"}" as &[u8]),
("data/info.txt", b"Version 1.0.0" as &[u8]),
];
create_zip("example.zip", &files)?;
println!("Created example.zip with {} files", files.len());
Ok(())
}use std::fs::File;
use std::io::Read;
use zip::ZipArchive;
fn list_zip_contents(path: &str) -> Result<(), Box<dyn std::error::Error>> {
let file = File::open(path)?;
let mut archive = ZipArchive::new(file)?;
println!("Archive contains {} files:", archive.len());
for i in 0..archive.len() {
let file = archive.by_index(i)?;
println!(
" {} ({} bytes, compressed: {} bytes)",
file.name(),
file.size(),
file.compressed_size()
);
}
Ok(())
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
list_zip_contents("example.zip")?;
Ok(())
}use std::fs::{self, File};
use std::io::{self, Read, Write};
use std::path::Path;
use zip::ZipArchive;
fn extract_zip(zip_path: &str, output_dir: &str) -> Result<(), Box<dyn std::error::Error>> {
let file = File::open(zip_path)?;
let mut archive = ZipArchive::new(file)?;
fs::create_dir_all(output_dir)?;
for i in 0..archive.len() {
let mut file = archive.by_index(i)?;
let outpath = Path::new(output_dir).join(file.name());
if file.name().ends_with('/') {
// Directory
fs::create_dir_all(&outpath)?;
} else {
// File
if let Some(p) = outpath.parent() {
if !p.exists() {
fs::create_dir_all(p)?;
}
}
let mut outfile = File::create(&outpath)?;
io::copy(&mut file, &mut outfile)?;
}
}
println!("Extracted {} files to {}", archive.len(), output_dir);
Ok(())
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
extract_zip("example.zip", "output")?;
Ok(())
}use std::fs::File;
use std::io::Read;
use zip::ZipArchive;
fn extract_single_file(
zip_path: &str,
file_name: &str,
) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
let file = File::open(zip_path)?;
let mut archive = ZipArchive::new(file)?;
let mut zip_file = archive.by_name(file_name)?;
let mut contents = Vec::new();
zip_file.read_to_end(&mut contents)?;
Ok(contents)
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let contents = extract_single_file("example.zip", "readme.txt")?;
println!("File contents: {}", String::from_utf8_lossy(&contents));
Ok(())
}use std::fs::File;
use std::io::prelude::*;
use zip::write::FileOptions;
use zip::{ZipWriter, CompressionMethod};
fn main() -> std::io::Result<()> {
let file = File::create("archive_with_dirs.zip")?;
let mut zip = ZipWriter::new(file);
let options = FileOptions::default()
.compression_method(CompressionMethod::Deflated);
// Add directory entries (must end with /)
zip.add_directory("src/", options.clone())?;
zip.add_directory("src/utils/", options.clone())?;
zip.add_directory("tests/", options.clone())?;
// Add files in directories
zip.start_file("src/main.rs", options.clone())?;
zip.write_all(b"fn main() { println!(\"Hello\"); }")?;
zip.start_file("src/utils/helper.rs", options.clone())?;
zip.write_all(b"pub fn help() { }")?;
zip.start_file("tests/test_main.rs", options.clone())?;
zip.write_all(b"#[test] fn test() { }")?;
zip.finish()?;
println!("Created archive with directory structure");
Ok(())
}use std::fs::File;
use std::io::prelude::*;
use zip::write::FileOptions;
use zip::{ZipWriter, CompressionMethod};
fn main() -> std::io::Result<()> {
let file = File::create("compression_test.zip")?;
let mut zip = ZipWriter::new(file);
// Different compression methods
let methods = vec![
("stored.txt", CompressionMethod::Stored, "No compression"),
("deflated.txt", CompressionMethod::Deflated, "Deflate compression"),
#[cfg(feature = "bzip2")]
("bzip2.txt", CompressionMethod::Bzip2, "Bzip2 compression"),
#[cfg(feature = "zstd")]
("zstd.txt", CompressionMethod::Zstd, "Zstd compression"),
];
// Sample data that compresses well
let data = "Hello, World! ".repeat(100);
for (name, method, description) in &methods {
let options = FileOptions::default()
.compression_method(*method);
zip.start_file(*name, options)?;
zip.write_all(data.as_bytes())?;
println!("Added {} ({})", name, description);
}
zip.finish()?;
// Compare file sizes
let metadata = std::fs::metadata("compression_test.zip")?;
println!("\nOriginal data: {} bytes", data.len());
println!("ZIP file: {} bytes", metadata.len());
Ok(())
}use std::fs::File;
use std::io::prelude::*;
use zip::write::FileOptions;
use zip::{ZipWriter, CompressionMethod};
fn main() -> std::io::Result<()> {
// Note: Compression level support depends on the backend
// and may require additional configuration
let file = File::create("compression_levels.zip")?;
let mut zip = ZipWriter::new(file);
// Sample data
let data = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. ".repeat(100);
// Default compression
let options = FileOptions::default()
.compression_method(CompressionMethod::Deflated);
zip.start_file("default.txt", options.clone())?;
zip.write_all(data.as_bytes())?;
// Fast compression (lower level)
let options_fast = FileOptions::default()
.compression_method(CompressionMethod::Deflated);
// Note: Actual compression level control may vary
zip.start_file("fast.txt", options_fast)?;
zip.write_all(data.as_bytes())?;
zip.finish()?;
println!("Created compression_levels.zip");
Ok(())
}use zip::ZipArchive;
fn print_zip_metadata(path: &str) -> Result<(), Box<dyn std::error::Error>> {
let file = File::open(path)?;
let archive = ZipArchive::new(file)?;
println!("ZIP Archive: {}", path);
println!("Number of files: {}", archive.len());
println!();
for i in 0..archive.len() {
let file = archive.by_index(i)?;
println!("File: {}", file.name());
println!(" Size: {} bytes", file.size());
println!(" Compressed: {} bytes", file.compressed_size());
println!(" Compression: {:?}", file.compression());
println!(" Modified: {:?}", file.last_modified());
println!(" Is directory: {}", file.is_dir());
println!(" Is file: {}", file.is_file());
println!(" Encrypted: {}", file.encrypted());
println!();
}
Ok(())
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
// First create a test archive
create_test_archive("test.zip")?;
print_zip_metadata("test.zip")?;
Ok(())
}
fn create_test_archive(path: &str) -> std::io::Result<()> {
use std::io::prelude::*;
use zip::write::FileOptions;
use zip::{ZipWriter, CompressionMethod};
let file = File::create(path)?;
let mut zip = ZipWriter::new(file);
let options = FileOptions::default()
.compression_method(CompressionMethod::Deflated);
zip.start_file("test.txt", options)?;
zip.write_all(b"Test content")?;
zip.finish()
}use std::fs::{File, OpenOptions};
use std::io::{Read, Seek, Cursor};
use zip::write::FileOptions;
use zip::{ZipArchive, ZipWriter, CompressionMethod};
fn append_to_zip(
zip_path: &str,
new_files: &[(&str, &[u8])],
) -> Result<(), Box<dyn std::error::Error>> {
// Read existing archive
let file = File::open(zip_path)?;
let mut archive = ZipArchive::new(file)?;
// Create new archive in memory
let mut buffer = Cursor::new(Vec::new());
{
let mut zip = ZipWriter::new(&mut buffer);
let options = FileOptions::default()
.compression_method(CompressionMethod::Deflated);
// Copy existing files
for i in 0..archive.len() {
let mut file = archive.by_index(i)?;
let name = file.name().to_string();
let is_dir = file.is_dir();
if is_dir {
zip.add_directory(&name, options.clone())?;
} else {
let mut contents = Vec::new();
file.read_to_end(&mut contents)?;
zip.start_file(&name, options.clone())?;
zip.write_all(&contents)?;
}
}
// Add new files
for (name, data) in new_files {
zip.start_file(*name, options.clone())?;
zip.write_all(data)?;
}
zip.finish()?;
}
// Write back to file
let mut file = OpenOptions::new()
.write(true)
.truncate(true)
.open(zip_path)?;
file.write_all(&buffer.into_inner())?;
Ok(())
}
use std::io::prelude::*;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create initial archive
let file = File::create("append_test.zip")?;
let mut zip = ZipWriter::new(file);
let options = FileOptions::default()
.compression_method(CompressionMethod::Deflated);
zip.start_file("original.txt", options.clone())?;
zip.write_all(b"Original content")?;
zip.finish()?;
// Append new files
let new_files = vec![
("added1.txt", b"Added content 1" as &[u8]),
("added2.txt", b"Added content 2" as &[u8]),
];
append_to_zip("append_test.zip", &new_files)?;
println!("Appended {} files", new_files.len());
Ok(())
}use std::fs::File;
use std::io::{Read, Cursor};
use zip::write::FileOptions;
use zip::{ZipArchive, ZipWriter, CompressionMethod};
fn modify_in_zip(
zip_path: &str,
file_name: &str,
modifier: impl Fn(&str) -> String,
) -> Result<(), Box<dyn std::error::Error>> {
let file = File::open(zip_path)?;
let mut archive = ZipArchive::new(file)?;
let mut buffer = Cursor::new(Vec::new());
{
let mut zip = ZipWriter::new(&mut buffer);
let options = FileOptions::default()
.compression_method(CompressionMethod::Deflated);
for i in 0..archive.len() {
let mut file = archive.by_index(i)?;
let name = file.name().to_string();
if name == file_name {
// Modify this file
let mut contents = String::new();
file.read_to_string(&mut contents)?;
let new_contents = modifier(&contents);
zip.start_file(&name, options.clone())?;
zip.write_all(new_contents.as_bytes())?;
} else {
// Copy unchanged
let mut contents = Vec::new();
file.read_to_end(&mut contents)?;
if file.is_dir() {
zip.add_directory(&name, options.clone())?;
} else {
zip.start_file(&name, options.clone())?;
zip.write_all(&contents)?;
}
}
}
zip.finish()?;
}
// Write back
let mut file = File::create(zip_path)?;
file.write_all(&buffer.into_inner())?;
Ok(())
}
use std::io::prelude::*;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create test archive
let file = File::create("modify_test.zip")?;
let mut zip = ZipWriter::new(file);
let options = FileOptions::default()
.compression_method(CompressionMethod::Deflated);
zip.start_file("data.txt", options.clone())?;
zip.write_all(b"Hello World")?;
zip.finish()?;
// Modify the file
modify_in_zip("modify_test.zip", "data.txt", |content| {
format!("{} - MODIFIED", content)
})?;
println!("Modified file in ZIP");
Ok(())
}use std::fs::File;
use std::io::prelude::*;
use zip::write::FileOptions;
use zip::{ZipWriter, CompressionMethod};
use zip::write::SimpleFileOptions;
fn create_encrypted_zip(
path: &str,
password: &[u8],
) -> std::io::Result<()> {
let file = File::create(path)?;
let mut zip = ZipWriter::new(file);
let options = FileOptions::default()
.compression_method(CompressionMethod::Deflated)
.with_deprecated_encryption(password);
zip.start_file("secret.txt", options)?;
zip.write_all(b"This is encrypted content")?;
zip.finish()?;
Ok(())
}
fn read_encrypted_zip(
path: &str,
password: &[u8],
) -> Result<String, Box<dyn std::error::Error>> {
let file = File::open(path)?;
let mut archive = zip::ZipArchive::new(file)?;
let mut file = archive.by_index_decrypt(0, password)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(contents)
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let password = b"secret123";
create_encrypted_zip("encrypted.zip", password)?;
println!("Created encrypted ZIP");
match read_encrypted_zip("encrypted.zip", password) {
Ok(contents) => println!("Decrypted contents: {}", contents),
Err(e) => println!("Failed to decrypt: {}", e),
}
// Try with wrong password
match read_encrypted_zip("encrypted.zip", b"wrong") {
Ok(contents) => println!("Unexpectedly decrypted: {}", contents),
Err(e) => println!("Wrong password rejected: {}", e),
}
Ok(())
}
use std::io::Read;use std::fs::{self, File};
use std::io::prelude::*;
use std::path::Path;
use walkdir::WalkDir;
use zip::write::FileOptions;
use zip::{ZipWriter, CompressionMethod};
fn compress_directory(
source_dir: &str,
output_zip: &str,
) -> Result<(), Box<dyn std::error::Error>> {
let file = File::create(output_zip)?;
let mut zip = ZipWriter::new(file);
let options = FileOptions::default()
.compression_method(CompressionMethod::Deflated);
let source_path = Path::new(source_dir);
for entry in WalkDir::new(source_dir) {
let entry = entry?;
let path = entry.path();
// Get relative path
let relative = path.strip_prefix(source_path)?;
if path.is_dir() {
// Add directory entry
let dir_name = relative.to_string_lossy() + "/";
if !dir_name.is_empty() {
zip.add_directory(&dir_name, options.clone())?;
}
} else {
// Add file
let file_name = relative.to_string_lossy();
zip.start_file(&file_name, options.clone())?;
let mut file = File::open(path)?;
std::io::copy(&mut file, &mut zip)?;
}
}
zip.finish()?;
Ok(())
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Note: Requires walkdir crate for recursive directory walking
// Add to Cargo.toml: walkdir = "2"
// compress_directory("./src", "src_backup.zip")?;
// println!("Created src_backup.zip");
println!("Example requires walkdir crate");
Ok(())
}use std::fs::{self, File};
use std::io::{self, Read, Write};
use std::path::Path;
use zip::ZipArchive;
fn extract_with_progress(
zip_path: &str,
output_dir: &str,
) -> Result<(), Box<dyn std::error::Error>> {
let file = File::open(zip_path)?;
let archive = ZipArchive::new(file)?;
let total_files = archive.len();
// Reopen for extraction (ZipArchive takes ownership)
let file = File::open(zip_path)?;
let mut archive = ZipArchive::new(file)?;
fs::create_dir_all(output_dir)?;
println!("Extracting {} files...", total_files);
for i in 0..archive.len() {
let mut file = archive.by_index(i)?;
let name = file.name().to_string();
let size = file.size();
print!("\r[{}/{}] Extracting: {} ({} bytes) ",
i + 1, total_files, name, size);
io::stdout().flush()?;
let outpath = Path::new(output_dir).join(&name);
if name.ends_with('/') {
fs::create_dir_all(&outpath)?;
} else {
if let Some(p) = outpath.parent() {
fs::create_dir_all(p)?;
}
let mut outfile = File::create(&outpath)?;
io::copy(&mut file, &mut outfile)?;
}
}
println!("\nDone!");
Ok(())
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
// extract_with_progress("large_archive.zip", "output")?;
println!("Run with a ZIP file to see progress");
Ok(())
}use std::fs::File;
use std::io::prelude::*;
use zip::write::FileOptions;
use zip::stream::{ZipWriter, CompressionMethod};
fn create_streaming_zip(
output_path: &str,
files: &[(&str, Vec<u8>)],
) -> std::io::Result<()> {
let file = File::create(output_path)?;
let mut zip = ZipWriter::new(file);
let options = FileOptions::default()
.compression_method(CompressionMethod::Deflated);
for (name, data) in files {
zip.start_file(*name, options.clone())?;
// Stream data in chunks
for chunk in data.chunks(1024) {
zip.write_all(chunk)?;
}
}
zip.finish()?;
Ok(())
}
fn main() -> std::io::Result<()> {
// Create large data
let large_data: Vec<u8> = (0..100_000).map(|i| (i % 256) as u8).collect();
let files = vec![
("large_file.bin", large_data),
];
create_streaming_zip("streaming.zip", &files)?;
println!("Created streaming.zip");
Ok(())
}
use zip::ZipWriter;use std::io::Cursor;
use std::io::prelude::*;
use zip::write::FileOptions;
use zip::{ZipWriter, ZipArchive, CompressionMethod};
fn create_zip_in_memory(files: &[(&str, &[u8])]) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
let mut buffer = Cursor::new(Vec::new());
{
let mut zip = ZipWriter::new(&mut buffer);
let options = FileOptions::default()
.compression_method(CompressionMethod::Deflated);
for (name, data) in files {
zip.start_file(*name, options.clone())?;
zip.write_all(data)?;
}
zip.finish()?;
}
Ok(buffer.into_inner())
}
fn read_zip_from_memory(data: &[u8]) -> Result<Vec<(String, Vec<u8>)>, Box<dyn std::error::Error>> {
let reader = Cursor::new(data);
let mut archive = ZipArchive::new(reader)?;
let mut files = Vec::new();
for i in 0..archive.len() {
let mut file = archive.by_index(i)?;
let name = file.name().to_string();
let mut contents = Vec::new();
file.read_to_end(&mut contents)?;
files.push((name, contents));
}
Ok(files)
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let files = vec![
("hello.txt", b"Hello, World!" as &[u8]),
("data.json", b"{\"key\": \"value\"}" as &[u8]),
];
// Create in memory
let zip_data = create_zip_in_memory(&files)?;
println!("Created ZIP in memory: {} bytes", zip_data.len());
// Read from memory
let extracted = read_zip_from_memory(&zip_data)?;
for (name, contents) in extracted {
println!("{}: {} bytes", name, contents.len());
println!(" Content: {:?}", String::from_utf8_lossy(&contents));
}
Ok(())
}
use std::io::Read;use std::fs::File;
use std::io::prelude::*;
use zip::write::FileOptions;
use zip::{ZipWriter, CompressionMethod};
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;
fn main() -> std::io::Result<()> {
let file = File::create("permissions.zip")?;
let mut zip = ZipWriter::new(file);
// Basic options
let options = FileOptions::default()
.compression_method(CompressionMethod::Deflated);
// With Unix permissions
#[cfg(unix)]
let options = FileOptions::default()
.compression_method(CompressionMethod::Deflated)
.unix_permissions(0o755); // rwxr-xr-x
zip.start_file("script.sh", options.clone())?;
zip.write_all(b"#!/bin/bash\necho Hello")?;
// Regular file with default permissions
zip.start_file("readme.txt", FileOptions::default()
.compression_method(CompressionMethod::Deflated))?;
zip.write_all(b"Readme content")?;
zip.finish()?;
println!("Created permissions.zip");
Ok(())
}use std::fs::{self, File};
use std::io::prelude::*;
use std::path::Path;
use zip::write::FileOptions;
use zip::{ZipWriter, CompressionMethod};
struct BackupConfig {
source: String,
output: String,
exclude: Vec<String>,
compression: CompressionMethod,
}
fn create_backup(config: &BackupConfig) -> Result<u64, Box<dyn std::error::Error>> {
let file = File::create(&config.output)?;
let mut zip = ZipWriter::new(file);
let options = FileOptions::default()
.compression_method(config.compression);
let source_path = Path::new(&config.source);
let mut total_bytes = 0u64;
let mut file_count = 0u64;
fn add_dir(
zip: &mut ZipWriter<File>,
dir: &Path,
base: &Path,
options: &FileOptions,
exclude: &[String],
stats: &mut (u64, u64),
) -> Result<(), Box<dyn std::error::Error>> {
for entry in fs::read_dir(dir)? {
let entry = entry?;
let path = entry.path();
let relative = path.strip_prefix(base)?;
// Check exclusions
let name = relative.to_string_lossy();
if exclude.iter().any(|e| name.starts_with(e)) {
continue;
}
if path.is_dir() {
add_dir(zip, &path, base, options, exclude, stats)?;
} else {
zip.start_file(relative.to_string_lossy(), options.clone())?;
let mut file = File::open(&path)?;
let bytes = std::io::copy(&mut file, zip)?;
stats.0 += 1;
stats.1 += bytes;
}
}
Ok(())
}
let mut stats = (0u64, 0u64);
add_dir(&mut zip, source_path, source_path, &options, &config.exclude, &mut stats)?;
zip.finish()?;
println!("Backup created: {} files, {} bytes", stats.0, stats.1);
Ok(stats.1)
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = BackupConfig {
source: ".".to_string(),
output: "backup.zip".to_string(),
exclude: vec!["target".to_string(), ".git".to_string()],
compression: CompressionMethod::Deflated,
};
create_backup(&config)?;
println!("Backup complete!");
Ok(())
}use std::fs::{self, File};
use std::io::{Read, prelude::*};
use std::path::PathBuf;
use zip::write::FileOptions;
use zip::{ZipArchive, ZipWriter, CompressionMethod};
struct ConfigArchive {
path: PathBuf,
}
impl ConfigArchive {
fn new(path: &str) -> Self {
Self { path: PathBuf::from(path) }
}
fn save(&self, configs: &[(String, String)]) -> std::io::Result<()> {
let file = File::create(&self.path)?;
let mut zip = ZipWriter::new(file);
let options = FileOptions::default()
.compression_method(CompressionMethod::Deflated);
for (name, content) in configs {
zip.start_file(format!("{}.conf", name), options.clone())?;
zip.write_all(content.as_bytes())?;
}
zip.finish()?;
Ok(())
}
fn load(&self) -> Result<Vec<(String, String)>, Box<dyn std::error::Error>> {
let file = File::open(&self.path)?;
let mut archive = ZipArchive::new(file)?;
let mut configs = Vec::new();
for i in 0..archive.len() {
let mut file = archive.by_index(i)?;
let name = file.name().to_string();
let mut content = String::new();
file.read_to_string(&mut content)?;
// Remove .conf extension
let name = name.trim_end_matches(".conf").to_string();
configs.push((name, content));
}
Ok(configs)
}
fn get(&self, name: &str) -> Result<Option<String>, Box<dyn std::error::Error>> {
let configs = self.load()?;
Ok(configs
.into_iter()
.find(|(n, _)| n == name)
.map(|(_, c)| c))
}
fn set(&self, name: &str, content: &str) -> Result<(), Box<dyn std::error::Error>> {
let mut configs = self.load().unwrap_or_default();
// Update or add
if let Some(pos) = configs.iter().position(|(n, _)| n == name) {
configs[pos].1 = content.to_string();
} else {
configs.push((name.to_string(), content.to_string()));
}
self.save(&configs)?;
Ok(())
}
fn list(&self) -> Result<Vec<String>, Box<dyn std::error::Error>> {
let configs = self.load()?;
Ok(configs.into_iter().map(|(n, _)| n).collect())
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let archive = ConfigArchive::new("configs.zip");
// Save some configs
archive.set("database", "host=localhost\nport=5432")?;
archive.set("server", "port=8080\nhost=0.0.0.0")?;
println!("Saved configs: {:?}", archive.list()?);
// Get a specific config
if let Some(db_config) = archive.get("database")? {
println!("Database config:\n{}", db_config);
}
Ok(())
}ZipWriter::new(file) to create a new ZIP archiveZipArchive::new(file) to read an existing archivezip.start_file(name, options) to add a filezip.add_directory(name, options) to add a directoryarchive.by_index(i) or archive.by_name(name) to read filesFileOptions::default().compression_method() sets compressionStored, Deflated, Bzip2, Zstd.with_deprecated_encryption(password) for password protection.name(), .size(), .compressed_size(), etc.Cursor<Vec<u8>>.is_dir() and .is_file() to check entry types