Create a ZIP Archive of a Folder in Python
Recursively zip all files in a folder into a single archive using the standard library zipfile and pathlib modules.
Python code
27 linesimport zipfile
from pathlib import Path
def zip_folder(source_dir: str, archive_path: str) -> None:
"""Zip all files in source_dir recursively into archive_path."""
source = Path(source_dir)
with zipfile.ZipFile(archive_path, "w", zipfile.ZIP_DEFLATED) as archive:
for file_path in source.rglob("*"):
if file_path.is_file():
# Store files relative to source directory
archive.write(file_path, file_path.relative_to(source))
if __name__ == "__main__":
# Create a test directory with some sample files
test_dir = Path("sample_folder")
test_dir.mkdir(exist_ok=True)
(test_dir / "readme.txt").write_text("Hello, world!")
(test_dir / "data.csv").write_text("name,value\nAlice,42\nBob,17\n")
sub_dir = test_dir / "subfolder"
sub_dir.mkdir(exist_ok=True)
(sub_dir / "config.json").write_text('{"enabled": true}')
# Zip the folder and print the contents of the archive
zip_folder("sample_folder", "sample_folder.zip")
with zipfile.ZipFile("sample_folder.zip") as archive:
for name in archive.namelist():
print(name)
Output
readme.txt
data.csv
subfolder/config.json
How it works
The Path.rglob("*") method walks the source directory recursively, yielding every file and directory. Only regular files are written to the archive, using archive.write(file_path, file_path.relative_to(source)) to store paths relative to the source root — this keeps the archive tidy and portable. zipfile.ZIP_DEFLATED enables compression for smaller archives. The context manager ensures the archive is properly closed and flushed to disk even if an error occurs.
Common mistakes
- Forgetting to filter for `is_file()`, which causes directory entries to be written with errors
- Using absolute paths in `arcname`, which bloats the archive with full filesystem paths
- Not specifying `ZIP_DEFLATED`, which leaves the archive uncompressed and much larger
- Using `rglob` on a source path with trailing slashes, which can produce inconsistent relative names
Variations
- Use `shutil.make_archive("sample_folder", "zip", "sample_folder")` for a one-liner alternative
- Add a `filter` to rglob, e.g. `source.rglob("*")` → `(p for p in source.rglob("*") if p.suffix in {".txt", ".csv"})`, to zip only certain file types
Real-world use cases
- Packaging project directories or logs for backup and offsite storage before a deployment.
- Creating downloadable artifacts from build outputs or test fixtures in CI pipelines.
- Bundling configuration files and assets for a microservice into a single deployable bundle.
Sponsored
More from Files & data
- Append a Line to a Log File in Python easy
- Audit File Permissions Across a Project in Python easy
- Automatically Detect Corrupted Files Using SHA-256 Checksums in Python easy
- Automatically Highlight Data Validation Errors Inside Excel Files in Python easy
- Build a Command-Line To-Do List Application with Data Persistence in Python easy
- Build a File Index by Relative Path Hash Map in Python easy
Keep learning
Related tutorials and quizzes for this topic.