Plate 84
tarfile vs zipfile Create+Extract: Localhost Lab
Hands-on tarfile vs zipfile create+extract lab: real MB/s on a mixed small-file fixture (uncompressed tar vs zip), measured on Linux localhost for SREs.
Aditya Challa4 min read
Intro — what this post promises
Pack and unpack the same tree with tarfile (uncompressed) vs zipfile (ZIP_STORED and ZIP_DEFLATED). This lab reports create/extract MB/s (payload ÷ wall) on Linux localhost.
It is not a remake of the zstd vs gzip vs lz4 localhost lab (stream codecs). Here the unit is an archive format — many small files, one create, one extract.
Related links:
- zstd vs gzip lz4 localhost lab
- scandir vs listdir localhost lab
- bytesio vs spooled tempfile localhost lab
- shutil copyfile vs manual localhost lab
- mmap vs read scan localhost lab
- glob vs rglob vs walk localhost lab
- secrets vs urandom localhost lab
- hashlib md5 vs blake2b localhost lab
Lab honesty (1 Oct 2026 IST): Python 3.13.5. Fixture ~7.81 MiB payload (40×50 × 4 KiB files + README). Affiliates: 0. No Docker. Compression stated per arm.
Verdict up front: create — zip stored ~64.3 MB/s vs tar ~52.3 vs zip deflated ~44.3. Extract — zip stored ~69.4 MB/s vs deflated ~63.9 vs tar ~29.3. Deflated archive size ~873 KiB vs stored ~8270 KiB vs tar ~11070 KiB.
Arms
| Arm | Compression |
|---|---|
tarfile.open(..., "w") | none (ustar) |
ZipFile ZIP_STORED | none (stored) |
ZipFile ZIP_DEFLATED | zlib deflate |
Lab topology
Script: lab-evidence/91-tarfile-vs-zipfile/results/run_lab.py.
Lead table — create (p50)
| Arm | s | MB/s payload | archive bytes |
|---|---|---|---|
| zip stored | 0.122 | 64.3 | 8468684 |
| tar uncompressed | 0.149 | 52.3 | 11335680 |
| zip deflated | 0.176 | 44.3 | 894178 |
Lead table — extract (p50)
| Arm | s | MB/s payload |
|---|---|---|
| zip stored | 0.113 | 69.4 |
| zip deflated | 0.122 | 63.9 |
| tar uncompressed | 0.266 | 29.3 |
Reading it
- ZIP_STORED won raw create/extract speed here — archive format overhead beat uncompressed tar on this many-small-files tree.
- ZIP_DEFLATED traded CPU for a much smaller archive (~9.47× smaller than stored on this compressible payload).
- Uncompressed tar was largest on disk (block padding) and slowest to extract in this run.
- Pick format for interop + tooling first; measure when installers/CI spend wall time on pack/unpack.
Compression clarity
This lab’s deflate is zipfile’s zlib, not standalone gzip/zstd stream APIs. For codec bake-offs see the zstd/gzip/lz4 post. For “ship a folder,” compare archive containers as done here.
Security note
tarfile.extractall used filter='data' (3.12+). Always constrain extracts from untrusted archives (path traversal). Throughput numbers do not make untrusted zips safe.
Many small files
Archive microbenches with one huge blob hide per-member overhead (headers, central directory, ustar padding). This fixture is intentionally many small files — closer to source trees and build artifacts. That is why uncompressed tar’s padded size and extract time looked worse than zip stored despite “no compression.”
When to deflate
Deflate paid ~45% create-time vs stored here but cut archive size dramatically on repetitive 4 KiB payloads. For already-compressed inputs (jpg, mp4, .whl), deflate often wastes CPU — prefer stored or an outer zstd layer designed for that job.
Pitfalls
- Comparing deflated zip speed to uncompressed tar without stating compression.
- Using tar.gz in one arm and forgetting CPU belongs to gzip, not tar.
- Ignoring archive size when “faster” stored zip is 10× larger on the wire.
- Extracting untrusted archives without filters.
Reproduce
Evidence: summary.json, fixture_tree/, archives/.
Limits
One Linux box. Synthetic compressible payloads. Not tar.gz/tar.zst, not ZIP_LZMA/BZIP2. Python stdlib only.
Takeaway
On this ~7.81 MiB small-file tree, zip stored create ~64.3 MB/s and extract ~69.4 MB/s led; deflate shrank the archive to ~873 KiB at ~44.3 MB/s create. Uncompressed tar lagged extract (~29.3 MB/s). Choose zip vs tar for ecosystem needs; measure when CI packs trees every build.
Lab evidence
What I found running this
Lab 1 Oct 2026 IST. Python 3.13.5. Fixture ~7.81 MiB. Create: zip_stored 64.3 MB/s; tar 52.3; zip_deflated 44.3. Extract: zip_stored 69.4; deflated 63.9; tar 29.3. Affiliates: 0. Evidence: lab-evidence/91-tarfile-vs-zipfile/.
Related links
Plate 18
fnmatch vs re Name Filter: Localhost Lab
Hands-on fnmatch.filter vs re.compile name-list filtering measured on Linux localhost.
Observability & SRE · 30 Sept 2026
Plate 85
scandir vs listdir vs iterdir: Localhost Lab
Hands-on os.scandir vs listdir vs Path.iterdir lab: real entries/s for names and is_file on a synthetic tree, measured on Linux localhost (lab) for SREs.
Observability & SRE · 30 Sept 2026
Plate 28
glob vs rglob vs os.walk: Listing Lab
Hands-on glob.glob vs Path.rglob vs os.walk lab: real files/s for recursive file listing on a modest fixture tree, measured on Linux localhost for SREs.
Observability & SRE · 30 Sept 2026