# xzip
`xzip` is a ZIP CLI focused on filename encoding control for cross-locale workflows.
It is designed for cases like:
- Archive created on a `zh_CN` Windows machine with WinRAR.
- Archive extracted on an `en_US` UTF-8 machine.
- Non-ASCII paths (CJK) become garbled without explicit encoding control.
`xzip` defaults to `utf-8` when `--encoding` is omitted, and you can still override it with `-e/--encoding` for cross-locale archives.
## Install
```bash
cargo install --locked xzip
```
### Man pages
Man pages are generated from the clap CLI definition via [`clap_mangen`](https://docs.rs/clap_mangen):
```bash
make man
# produces man/xzip.1, man/xzip-pack.1, man/xzip-unpack.1, man/xzip-list.1
man -l man/xzip.1
man -l man/xzip-pack.1
```
Install man pages system-wide (requires root for `/usr/local`):
```bash
sudo make install-man
man xzip
```
## Usage
```bash
# Pack a directory with explicit filename encoding
xzip pack -i ./my-dir -o ./my-dir.zip -e gbk -r
# List archive contents before extracting
xzip list -i ./my-dir.zip -e gbk
xzip ls -i ./my-dir.zip
# Unpack with explicit filename encoding
xzip unpack -i ./my-dir.zip -o ./out -e gbk
# Parallel unpack is automatic for large archives (no flag needed)
xzip unpack -i ./my-dir.zip -o ./out
# Force sequential extraction
xzip unpack -j 1 -i ./my-dir.zip -o ./out
# Force 4 worker threads
xzip unpack -j 4 -i ./my-dir.zip -o ./out
# Show progress, jobs used, and elapsed time
xzip unpack -v -i ./my-dir.zip -o ./out -e gbk
# Show per-phase timings (scan / mkdir / extract)
xzip unpack --profile -i ./my-dir.zip -o ./out
xzip pack -v -i ./my-dir -o ./my-dir.zip -r
# Omit encoding (defaults to utf-8)
xzip pack -i ./my-dir -o ./my-dir.zip -r
```
## List
`list` (alias `ls`) prints an `unzip -l` style table to stdout:
```bash
xzip list -i ./archive.zip -e gbk
```
Example output:
```
Length Date Time Name
--------- ---------- ----- ----
1234 2026-07-09 09:00 aa/file.txt
0 2026-07-09 09:00 aa/subdir/
--------- -------
1234 2 files
```
Use the same `--include` / `--exclude` globs as `unpack` to preview a filtered subset.
## Verbose output
`-v` and `-vv` are global flags (repeatable). Progress messages go to stderr; `list` tables stay on stdout.
| default | silent | silent | table |
| `-v` | `adding: path` + summary | throttled `extracting: N/M files...` + summary | table + Compressed column |
| `-vv` | bytes + compression method | per-file `uncompressed -> compressed` bytes | table + Method column |
`pack` and `unpack` are silent by default. Use `-v` when you want progress and a final timing summary.
Parallel extraction (`-j/--jobs`) is enabled automatically for large archives (256+ files and 4+ MiB uncompressed). Use `-j 1` to force sequential extraction, or `-j N` for a specific thread count. `-vv` always uses a single thread so per-file output stays ordered. On Windows, auto mode caps parallel writers at 4 threads to reduce NTFS and antivirus contention.
`-v` summary includes the effective job count, for example: `6313 files extracted (1251 directories) in 5.22s [jobs=8]`. Use `--profile` to print scan/mkdir/extract phase timings.
## Common options
- `-r, --recursive` (pack only): include nested files/directories.
- `-j, --jobs <N>` (unpack only): `0` = auto (default), `1` = sequential, `N` = thread count.
- `--profile` (unpack only): print per-phase timings to stderr.
- `--include <GLOB>`: only process matching paths. Repeatable.
- `--exclude <GLOB>`: skip matching paths. Repeatable.
Example:
```bash
xzip pack -i ./project -o ./project.zip -e utf-8 -r \
--exclude ".git/**" \
--exclude "target/**" \
--include "**/*.rs"
```
## Supported encodings
- `utf-8` (`utf8`, `unicode`)
- `gbk` (`cp936`, `936`)
- `shift_jis` (`shift-jis`, `sjis`, `cp932`)
## Why explicit encoding
Many archive tools infer filename encoding from locale or ZIP flags. In mixed environments this can produce corrupted paths during extraction. `xzip` makes the encoding choice explicit at runtime.
## Windows performance
Extracting archives with thousands of small files on native Windows + NTFS is often much slower than on Linux. This is usually not a deflate bottleneck. Windows Defender and NTFS per-file metadata work dominate when `xzip` creates many files.
Typical symptoms:
- VS Code / IDE / `node_modules`-style archives take tens of seconds on Windows but only a few seconds on Linux
- `-j 1` and auto mode take similar time, which means the bottleneck is per-file writes rather than thread scheduling
What helps most:
1. Add the output directory to Microsoft Defender exclusions (largest gain)
2. On Windows 11, extract to a Dev Drive with Defender performance mode enabled
3. If the zip was downloaded from a browser, right-click it → Properties → check **Unblock**
4. Use `xzip unpack --profile` to confirm whether time is spent in `extract` vs `scan`/`mkdir`
Example:
```bash
xzip unpack -v --profile -i VSCode-win32-x64.zip -o D:\dev\vsc
```
Diagnostic commands:
```powershell
# Compare auto vs sequential
xzip unpack -v -i archive.zip -o out-auto
xzip unpack -v -j 1 -i archive.zip -o out-seq
# Force a specific thread count
xzip unpack -j 4 -i archive.zip -o out-j4
```
If Defender exclusions are not an option, expect large archives to remain slower on Windows than on Linux even with `xzip` optimizations.