ozip is a fast, parallel zip compression tool written in Go. Drop-in replacement for zip with smart defaults, powerful exclusion patterns, and production-ready reliability.
Contact us and let us know on how many servers you'd like to use it so you can get you a good price for it.
# ozip vs zip: Full Comparison
## Test Setup
```
testdir/
├── root.log
├── keep.txt
├── dir1/
│ ├── level1.log
│ └── dir2/
│ ├── level2.log
│ └── dir3/
│ ├── level3.log
│ └── level3.txt
├── logs/
│ └── app.log
└── deep/
└── nested/
└── path/
└── file.LOG
```
## Exclude Pattern Behavior
| Behavior | zip (Info-ZIP) | ozip |
|---|---|---|
| Case sensitivity | Case-sensitive | Case-insensitive |
| `*` crosses `/` | **Yes** | **No** |
| Simple pattern (`*.log`) matches all levels | Yes | Yes (basename match) |
| Path pattern (`dir1/*.log`) | Matches ALL depths under dir1/ | Matches only `dir1/level1.log` |
| Trailing `/` = directory only | No effect | Yes |
| Regex support | No | Yes (`--app-xr`) |
## Test Results
### Simple pattern: `*.log`
**zip:** Excludes `root.log`, `level1.log`, `level2.log`, `level3.log`, `app.log`. Does NOT exclude `file.LOG` (case-sensitive).
**ozip:** Excludes all of the above AND `file.LOG` (case-insensitive).
### Path pattern: `dir1/*.log` — the key difference
**zip:** Excludes `dir1/level1.log`, `dir1/dir2/level2.log`, AND `dir1/dir2/dir3/level3.log`. The `*` crosses `/` boundaries, matching all `.log` files at any depth under `dir1/`.
**ozip:** Excludes only `dir1/level1.log`. The `*` stays within a single path segment (Go's `filepath.Match` behavior). To exclude all depths, use regex: `--app-xr 'dir1/.*\.log$'`.
### Wildcard `dir1/*` — crosses all levels in zip
**zip:** `dir1/*` excludes the entire `dir1/` subtree — all files and subdirectories at every depth.
**ozip:** `dir1/*` excludes only direct children of `dir1/` (one level). For the full subtree, use `dir1/` (trailing slash) or `--app-xr 'dir1/'`.
### Case sensitivity: `*.LOG`
**zip:** Only excludes `file.LOG`. Does NOT exclude `.log` files.
**ozip:** Excludes ALL `.log` and `.LOG` files. Both pattern and path are lowercased before matching.
### Directory-only: `dir2/`
**zip:** Trailing slash has no special effect. `dir2/` did NOT exclude the `dir2` directory — it was still included in the archive.
**ozip:** Trailing slash restricts the pattern to directories only. `dir2/` excludes the directory and its entire subtree.
## Summary
### Where ozip improves on zip
**Case-insensitive matching.** A single `-x '*.log'` catches `file.log`, `FILE.LOG`, `debug.Log`, and every variation. On web servers where file naming is inconsistent, this prevents files from slipping through.
**Predictable `*` behavior.** In zip, `dir1/*.log` silently matches 3 levels deep. In ozip, `*` always means one path segment — no surprises. When you need multi-level matching, use regex (`--app-xr`) which makes the intent explicit.
**Directory-only patterns.** Trailing `/` in ozip excludes directories and their subtrees. In zip, trailing `/` has no effect — you need `dir/*` instead, which also crosses boundaries unpredictably.
**Regex support.** ozip's `--app-xr` flag provides full regex exclusions for complex patterns that globs can't express:
```bash
# Exclude all cache and backup directories
ozip --app-xr '(cache|backup|\.tmp)/' archive.zip .
# Exclude log files only in wp-content
ozip --app-xr 'wp-content/.*\.log$' archive.zip .
```
### Where zip differs
**`*` crosses `/` boundaries.** This can be convenient (`dir1/*` excludes the whole subtree) but also dangerous — `*.log` in a path pattern may match more files than expected at deeper levels.
**Case-sensitive.** Matches exactly what you type. Requires separate patterns for `*.log` and `*.LOG` if both exist.
## Beyond Exclude Patterns
### Compression
| Feature | zip (Info-ZIP) | ozip |
|---|---|---|
| Parallel compression | No (single-threaded) | Yes (multi-core, configurable workers) |
| Compression levels | 0-9 (level 6 default) | 0-9 (level 6 default) |
| Smart store for compressed files | No (re-compresses .jpg, .mp4, .gz) | Yes (auto-detects and stores at level 0) |
| Streaming compression | Buffered but single-pass | Buffered I/O (256 KB) with parallel workers |
zip uses a single thread. ozip uses all available CPU cores by default with a parallel pipeline: feeder -> N workers -> sequential writer. Each worker compresses independently using `CreateRaw` with pre-compressed data. On multi-core servers, ozip is significantly faster on large directory trees.
ozip auto-detects already-compressed files (.jpg, .png, .mp4, .gz, .zip, .rar, .woff2, .pdf, .docx, etc.) and stores them at level 0 instead of wasting CPU. zip re-compresses everything regardless.
### Archive Operations
| Feature | zip (Info-ZIP) | ozip |
|---|---|---|
| Update existing archive (`-u`) | Yes | Yes |
| Freshen existing files (`-f`) | Yes | Yes |
| Test archive integrity (`-T`) | Yes | Yes (CRC32 verification) |
| Password protection | Yes (ZipCrypto, weak) | Yes (via 7z: AES-256, .7z also encrypts filenames) |
| 7z format support | No | Yes (delegates to external 7z binary) |
| Archive comment | Yes (`-z`) | Yes (`--app-comment` or `OZIP_COMMENT`) |
| Junk paths (`-j`) | Yes | Yes |
| Zip directory prefix | No | Yes (`--app-zip-dir-prefix`) |
| Stdout output | Yes (`-`) | Yes (`-`) |
zip's built-in encryption uses ZipCrypto which is known to be weak and crackable. ozip delegates to 7z for AES-256 encryption. When using .7z format, filenames are also encrypted.
### Reliability
| Feature | zip (Info-ZIP) | ozip |
|---|---|---|
| Atomic writes on update | No | Yes (temp file + fsync + rename) |
| Signal cleanup | No (leaves partial archive) | Yes (SIGTERM/SIGINT removes partial file) |
| Disk space check | No | Yes (`--app-check-disk-space`) |
| File locking | No | Yes (shared read locks with 30s timeout) |
| `fsync` before reporting success | No | Yes |
| Self-exclusion | No (can archive itself) | Yes (auto-detects output file in source tree) |
zip writes directly to the output. If the process is killed, you get a corrupted archive. ozip uses temp file + fsync + atomic rename for update/freshen operations, and removes partial archives on signal interrupt.
ozip automatically detects when the output archive is inside the source directory and excludes it. zip will happily include itself in the archive, causing corruption or infinite growth.
### Automation
| Feature | zip (Info-ZIP) | ozip |
|---|---|---|
| Lifecycle hooks | No | Yes (pre/post/complete/error) |
| Email notifications | No | Yes (`--app-notify-email`) |
| Dry run | No | Yes (`--app-dry-run`) |
| Progress output | No | Yes (`--app-progress`) |
| Nice level | External (`nice -n 10 zip ...`) | Built-in (`--app-nice 10`) |
| Quiet mode (`-q`) | Yes | Yes |
| Regex exclusions | No | Yes (`--app-xr`) |
| Environment variable config | `ZIPOPT` for default flags | Full config: OZIP_LEVEL, OZIP_WORKERS, OZIP_COMMENT, etc. |
ozip hooks enable automated backup workflows:
```bash
ozip --app-pre-hook 'echo "Starting backup"' \
--app-complete-hook 'rsync $OZIP_ARCHIVE remote:backups/' \
--app-error-hook 'curl -X POST https://alerts.example.com' \
--app-notify-email admin@example.com \
--app-nice 10 \
backup.zip /var/www
```
### Deployment
| Feature | zip (Info-ZIP) | ozip |
|---|---|---|
| Installation | Package manager (`apt install zip`) | Single static binary, zero dependencies |
| Self-update | No | Yes (`ozip cli update`) |
| Cross-platform binary | Separate packages per OS | Linux + macOS from single build script |
| Thread safety on constrained servers | N/A (single-threaded) | Auto-caps workers based on `ulimit -u` |
| Last updated | 2008 (Zip 3.0) | Actively maintained |
Info-ZIP's last release was 2008. ozip is actively maintained with modern Go, parallel compression, and features designed for current server environments.
### When to use zip
- Maximum compatibility — zip is pre-installed on most systems
- You need ZipCrypto encryption specifically (some legacy systems require it)
- Simple one-off compression where speed doesn't matter
### When to use ozip
- Speed matters — parallel compression on multi-core servers
- Large web sites with thousands of files (.jpg, .mp4 auto-detected)
- Backup automation with hooks, email, error handling
- Shared hosting with low `ulimit -u` — ozip auto-adjusts worker count
- Stronger encryption (AES-256 via 7z)
- You want case-insensitive, predictable exclude patterns
- Single binary with self-update — no package manager needed
# ozip vs tar: Full Comparison
## Test Setup
```
tartest/
├── root.log
├── keep.txt
├── dir1/
│ ├── level1.log
│ └── dir2/
│ ├── level2.log
│ └── dir3/
│ ├── level3.log
│ └── level3.txt
├── logs/
│ └── app.log
└── deep/
└── nested/
└── path/
└── file.LOG
```
## Exclude Pattern Behavior
| Behavior | tar (bsdtar) | ozip |
|---|---|---|
| Case sensitivity | Case-sensitive | Case-insensitive |
| `*` crosses `/` | No | No |
| Simple pattern (`*.log`) matches all levels | Yes | Yes (basename match) |
| Path pattern (`dir1/*.log`) | Matches only `dir1/level1.log` | Matches only `dir1/level1.log` |
| Trailing `/` = directory only | Yes | Yes |
| Regex support | No | Yes (`--app-xr`) |
## Test Results
### Simple pattern: `*.log`
Both tar and ozip exclude `.log` files at every directory level.
**tar:** Excludes `root.log`, `level1.log`, `level2.log`, `level3.log`, `app.log`. Does NOT exclude `file.LOG`.
**ozip:** Excludes all of the above AND `file.LOG` (case-insensitive).
### Path pattern: `dir1/*.log`
Both tar and ozip only match one level deep — `*` does not cross `/`.
**tar:** Excludes only `dir1/level1.log`. Does NOT exclude `dir1/dir2/level2.log` or deeper.
**ozip:** Same behavior. `filepath.Match` treats `*` as a single path segment.
### Case sensitivity: `*.LOG`
**tar:** Only excludes `file.LOG`. Does NOT exclude `root.log`, `level1.log`, etc.
**ozip:** Excludes ALL `.log` and `.LOG` files. ozip lowercases both pattern and path before matching.
### Directory-only: `dir2/`
**tar:** Excludes the entire `dir2/` directory and its subtree.
**ozip:** Same behavior. Trailing `/` restricts the pattern to directories only.
## Key Differences
### Case-insensitive matching (ozip)
ozip always matches case-insensitively. This is intentional for web hosting environments where file naming is inconsistent (e.g. `image.JPG`, `backup.Sql`, `FILE.LOG`). A single `-x '*.log'` catches all variations.
tar requires `--ignore-case` (GNU tar only) or separate patterns for each case variation.
### Regex support (ozip only)
ozip supports regex exclusions via `--app-xr`:
```bash
ozip --app-xr 'node_modules/' archive.zip .
ozip --app-xr '\.(log|tmp|bak)$' archive.zip .
```
tar has no built-in regex support for exclusions.
### Suffix sliding (ozip)
For path patterns containing `/`, ozip tries the pattern against the full path and every suffix. This means `*/wp-content/*cache*/` matches `public_html/wp-content/cache-fast/` even with extra leading segments.
tar matches the pattern against the member name as stored in the archive.
### GNU tar vs bsdtar
GNU tar's default is `--wildcards-match-slash` for exclusions, meaning `*` can cross `/` boundaries. bsdtar (macOS) does NOT let `*` cross `/`. ozip behaves like bsdtar — `*` stays within a single path segment.
## Beyond Exclude Patterns
### Compression
| Feature | tar | ozip |
|---|---|---|
| Format | tar (uncompressed), tar.gz, tar.bz2, tar.xz | zip, 7z (via external 7z binary) |
| Parallel compression | No (single-threaded) | Yes (multi-core, configurable workers) |
| Compression levels | Depends on compressor (gzip -1 to -9) | 0-9 (level 6 default) |
| Smart store for compressed files | No | Yes (auto-detects .jpg, .zip, .mp4, etc. and stores at level 0) |
tar compresses with a single thread. ozip uses all available CPU cores by default, with a parallel pipeline: feeder goroutine -> N worker goroutines -> sequential writer. On a 4-core machine compressing a large site, ozip can be 3-4x faster.
ozip auto-detects already-compressed files (.jpg, .png, .mp4, .gz, .zip, etc.) and stores them at level 0 instead of wasting CPU trying to recompress them.
### Archive Operations
| Feature | tar | ozip |
|---|---|---|
| Update existing archive (`-u`) | Yes | Yes |
| Freshen existing files (`-f`) | No | Yes (only replace older, no new files) |
| Test archive integrity (`-T`) | No built-in | Yes (CRC32 verification) |
| Password protection | No | Yes (via 7z backend) |
| Archive comment | No | Yes (`--app-comment`) |
| Junk paths (`-j`) | No | Yes (store files without directory structure) |
| Zip directory prefix | No | Yes (`--app-zip-dir-prefix`) |
### Reliability
| Feature | tar | ozip |
|---|---|---|
| Atomic writes | No (partial file on interrupt) | Yes (temp file + rename) |
| Signal cleanup | No (leaves partial archive) | Yes (SIGTERM/SIGINT removes partial archive) |
| Disk space check | No | Yes (`--app-check-disk-space`) |
| File locking | No | Yes (shared read locks with timeout) |
| `fsync` before reporting success | No | Yes |
tar writes directly to the output file. If interrupted (Ctrl+C, kill), you get a partial corrupted archive. ozip writes to a temp file first, calls `fsync`, then atomically renames. On interrupt, the signal handler removes the partial temp file — you never get a half-written archive.
### Automation
| Feature | tar | ozip |
|---|---|---|
| Lifecycle hooks | No | Yes (pre/post/complete/error) |
| Email notifications | No | Yes (`--app-notify-email`) |
| Dry run | No | Yes (`--app-dry-run`) |
| Progress output | No | Yes (`--app-progress`) |
| Nice level | External (`nice -n 10 tar ...`) | Built-in (`--app-nice 10`) |
| Environment variable config | No | Yes (OZIP_LEVEL, OZIP_WORKERS, etc.) |
ozip hooks run shell commands at key lifecycle points and receive environment variables (archive path, file count, bytes written, elapsed time). This enables cron-based backup workflows:
```bash
ozip --app-pre-hook 'echo "Starting backup"' \
--app-complete-hook 'rsync $OZIP_ARCHIVE remote:backups/' \
--app-error-hook 'curl -X POST https://alerts.example.com' \
--app-notify-email admin@example.com \
backup.zip /var/www
```
### Deployment
| Feature | tar | ozip |
|---|---|---|
| Installation | Pre-installed on all Unix systems | Single static binary, zero dependencies |
| Self-update | No | Yes (`ozip cli update`) |
| Cross-platform binary | N/A | Linux + macOS from single build script |
| Thread safety on constrained servers | N/A | Auto-caps workers based on `ulimit -u` |
### When to use tar
- You need tar format specifically (e.g. Docker images, Linux packages)
- tar.xz for maximum compression ratio (xz compresses better than deflate)
- You need to preserve Unix permissions, ownership, and extended attributes exactly
- The archive will be extracted on Unix systems only
### When to use ozip
- You need zip format (cross-platform, Windows compatibility)
- Speed matters — parallel compression on multi-core servers
- Backup automation with hooks, email notifications, and error handling
- Web hosting with low `ulimit -u` — ozip auto-adjusts
- You want a single binary with self-update, no package manager needed