s-zip
███████╗ ███████╗██╗██████╗
██╔════╝ ╚══███╔╝██║██╔══██╗
███████╗█████╗ ███╔╝ ██║██████╔╝
╚════██║╚════╝ ███╔╝ ██║██╔═══╝
███████║ ███████╗██║██║
╚══════╝ ╚══════╝╚═╝╚═╝
High-performance streaming ZIP library for Rust backends. Process multi-gigabyte archives with constant ~5MB memory usage.
Features
- 🚀 Streaming I/O - Constant memory regardless of archive size
- 🔐 AES-256 Encryption - WinZip-compatible password protection (sync + async)
- ⚡ Async/Await - Full Tokio support with encryption
- 🌩️ Cloud Storage - Direct streaming to/from S3, GCS, MinIO
- 💪 Parallel Compression - 2-4x speedup on multi-core CPUs
- 📦 ZIP64 - Files >4GB supported
- 🗜️ Multiple Codecs - DEFLATE, Zstd (3x faster compression)
Quick Start
[]
= "0.11"
# With all features
= { = "0.11", = ["async", "encryption", "async-zstd", "cloud-all"] }
Basic Usage
use ;
// Write
let mut writer = new?;
writer.start_entry?;
writer.write_data?;
writer.finish?;
// Read
let mut reader = open?;
let data = reader.read_entry_by_name?;
Async with Encryption
use AsyncStreamingZipWriter;
async
Cloud Storage (S3/GCS)
use ;
use Client;
let config = load_from_env.await;
let s3_client = new;
let writer = builder
.client
.bucket
.key
.build
.await?;
let mut zip = from_writer;
zip.start_entry.await?;
zip.write_data.await?;
zip.finish.await?;
What's New in v0.11.3
⚡ Performance & DRY refactor — zero-copy parallel compression, streaming decrypt, proptest coverage:
-
True zero-copy parallel compression —
compress_file_deflateinparallel.rspreviously buffered the entire file into RAM before compressing. NewCrcReaderwrapper computes CRC32 on-the-fly through aFile → BufReader(64KB) → CrcReader → DeflateEncoderpipeline. Peak RAM per task is now ~96 KB regardless of file size (was full file size × concurrency). Measured: 20 files × 5MB with 8 threads → ~16 MB peak (was ~320 MB). -
Streaming decryption —
read_entry_streaming()on both sync and async readers now supports encrypted entries via newDecryptingReader<R>/AsyncDecryptingReader<R>wrappers. Call.finish()after reading to verify the HMAC-SHA1 tag. -
Shared
format.rsmodule — ZIP constants,ZipEntry, and pure parsing helpers extracted from duplicatedreader.rs/async_reader.rs. ~300 lines of duplicate code removed. -
Proptest fuzz coverage — 6 property tests in
tests/proptest_zip_parsing.rsverifyfind_eocd_in_buffer,find_zip64_eocd_offset, andparse_zip64_extra_fieldnever panic on arbitrary input.
Breaking Changes: None.
Migration from v0.11.2:
= { = "0.11.3", = ["async", "encryption"] }
Performance
Single-threaded (1MB compressible data, DEFLATE level 6):
- Write: ~1.5 ms → ~680 MB/s
- Async write: ~2.2 ms (~1.5× overhead vs sync at 1MB, converges at larger sizes)
Parallel compression (20 files × 5MB = 100MB):
- 2 threads: 731 MB/s, peak RAM 3 MB
- 4 threads: 2484 MB/s, peak RAM 2 MB
- 8 threads: 1434 MB/s, peak RAM 3 MB
- Process total peak RSS: 16 MB (bounded regardless of file size)
Memory: ~16 MB process peak even compressing 100MB in parallel (8 threads).
See CHANGELOG.md for full details.
Optional Features
| Feature | Description |
|---|---|
encryption |
AES-256 encryption (sync + async) |
async |
Tokio async/await support |
async-zstd |
Async Zstd compression |
zstd-support |
Sync Zstd compression |
cloud-s3 |
AWS S3 / MinIO streaming |
cloud-gcs |
Google Cloud Storage streaming |
cloud-all |
All cloud providers |
Examples
Encryption (including streaming decrypt):
// Write encrypted
let mut writer = new?;
writer.set_password;
writer.start_entry?;
writer.write_data?;
writer.finish?;
// Read encrypted — full (HMAC verified before any bytes returned)
let mut reader = open?;
reader.set_password;
let data = reader.read_entry_by_name?;
// Read encrypted — streaming (decrypt on-the-fly, call finish() to verify HMAC)
let entry = reader.find_entry.unwrap.clone;
let mut stream = reader.read_entry_streaming?;
copy?;
// stream is dropped here; HMAC is verified in DecryptingReader::finish()
Zstd Compression:
let mut writer = with_zstd?;
writer.start_entry?;
writer.write_data?;
writer.finish?;
Parallel Compression:
use ;
let entries = vec!;
let config = balanced; // 4 threads
let mut writer = new.await?;
writer.write_entries_parallel.await?;
writer.finish.await?;
In-Memory ZIP:
let buffer = Vecnew;
let cursor = new;
let mut writer = from_writer?;
writer.start_entry?;
writer.write_data?;
let cursor = writer.finish?;
let zip_bytes = cursor.into_inner;
More examples in examples/ directory.
Use Cases
- Web APIs - Generate ZIPs on-demand (Axum, Actix, Rocket)
- Cloud Pipelines - Stream directly to S3/GCS without local disk
- Data Exports - Large dataset exports with encryption
- ETL Jobs - Batch processing with bounded memory
- Microservices - Streaming responses over HTTP
Documentation
- API Docs: https://docs.rs/s-zip
- Performance: BENCHMARK_RESULTS.md
- Examples: examples/
- Changelog: CHANGELOG.md
Non-Goals
- Not a CLI tool (use
zip/unzipfor that) - Not optimized for small files (<1KB)
- Not focused on desktop/GUI usage
License
MIT License - see LICENSE
Contributing
Contributions welcome! Please feel free to submit a Pull Request.
Author
Ton That Vu - @KSD-CO