Python zipfile Module

Learn the Python zipfile module with examples. Create and append ZIP archives, list and read members, extract files safely, handle passwords on read, choose compression, use BytesIO, and rebuild archives without a member.

Published

Updated

Read time 7 min read

Reviewed byDeepak Prasad

Python zipfile Module

The Python zipfile module works with .zip archive files on disk or in memory: create archives, add files, list members, read contents, and extract. It is not the built-in zip() function, which pairs items from iterables into tuples. The similar names confuse beginners—remember zipfile = archive files, zip() = combine lists.

Tested on: Python 3.13.3; kernel 6.14.0-37-generic.


Python zipfile quick reference

Task Method / class
Open a ZIP archive ZipFile()
Create a new ZIP file ZipFile(..., 'w')
Add a file write()
Add text or bytes as a file writestr()
List file names namelist()
List file metadata infolist()
Read a file without extracting read() or open()
Extract one file extract()
Extract all files extractall()
Test archive integrity testzip()
Read metadata for one file getinfo()
Work with large ZIP files allowZip64=True

zipfile vs zip(): what is the difference?

Built-in zip() zipfile module
Purpose Pair iterables by index Read/write .zip archives
Import Always available import zipfile
Typical output Iterator of tuples Files on disk or bytes in memory

The built-in zip() pairs iterables; see that article for strict=True and zip_longest() when you need tuple-wise iteration instead of archive I/O.


Import Python zipfile module

python
import zipfile
from zipfile import ZipFile
Output

No pip install is required—zipfile ships with Python. The ZipFile class is the main entry point; use it as a context manager (with ZipFile(...) as zf:) so the archive closes reliably.


Create a ZIP file in Python

Open ZipFile in write mode ('w'). That creates a new archive or overwrites an existing file at the same path. Confirm the destination path with check if a file exists when you must avoid clobbering an unrelated file at the same name.

python
import tempfile
import zipfile
from pathlib import Path

with tempfile.TemporaryDirectory() as tmp:
    src = Path(tmp) / "hello.txt"
    src.write_text("Hello ZIP\n")
    zip_path = Path(tmp) / "demo.zip"

    with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf:
        zf.write(src, arcname="hello.txt")
        zf.writestr("notes.txt", "Inline text\n")

    with zipfile.ZipFile(zip_path) as zf:
        print(zf.namelist())

You should see ['hello.txt', 'notes.txt']. The arcname argument controls the path inside the archive; without it, write() uses the source file’s basename.

writestr() adds a member from a str or bytes value when you do not have a separate file on disk.


Add files to an existing ZIP file

Use append mode ('a') to add entries to an existing archive without rebuilding the whole file:

python
import tempfile
import zipfile
from pathlib import Path

with tempfile.TemporaryDirectory() as tmp:
    zip_path = Path(tmp) / "demo.zip"
    with zipfile.ZipFile(zip_path, "w") as zf:
        zf.writestr("a.txt", "first")

    with zipfile.ZipFile(zip_path, "a") as zf:
        zf.writestr("b.txt", "second")

    with zipfile.ZipFile(zip_path) as zf:
        print(zf.namelist())

You should see both names. Append adds new entries; it does not remove old ones. If you writestr() or write() with an arcname that already exists, you can end up with duplicate member names in one archive—avoid reusing the same internal path unless you intend to replace via a rebuild.


List files inside a ZIP archive

python
import tempfile
import zipfile
from pathlib import Path

with tempfile.TemporaryDirectory() as tmp:
    zip_path = Path(tmp) / "demo.zip"
    with zipfile.ZipFile(zip_path, "w") as zf:
        zf.writestr("data/report.csv", "a,b\n1,2\n")

    with zipfile.ZipFile(zip_path) as zf:
        print(zf.namelist())
        for info in zf.infolist():
            print(info.filename, info.file_size, info.compress_size)
        one = zf.getinfo("data/report.csv")
        print(one.filename, one.file_size)
  • namelist() — member paths as strings
  • infolist()ZipInfo objects (size, compression, date, etc.)
  • getinfo(name) — metadata for one member (raises KeyError if missing)

printdir() prints a human-readable listing when you are exploring interactively.


Read files from ZIP without extracting

read(name) returns the member as bytes. open(name) returns a file-like object—better for large files or line-by-line reads:

python
import tempfile
import zipfile
from pathlib import Path

with tempfile.TemporaryDirectory() as tmp:
    zip_path = Path(tmp) / "demo.zip"
    with zipfile.ZipFile(zip_path, "w") as zf:
        zf.writestr("hello.txt", "Hello ZIP\n")

    with zipfile.ZipFile(zip_path) as zf:
        print(zf.read("hello.txt"))
        with zf.open("hello.txt") as f:
            print(f.read())

Both calls return b'Hello ZIP\n'. Decode with .decode() when you expect text. Prefer open() when the member is large so you stream instead of loading everything into memory.


Extract ZIP files in Python

python
import tempfile
import zipfile
from pathlib import Path

with tempfile.TemporaryDirectory() as tmp:
    zip_path = Path(tmp) / "demo.zip"
    out_dir = Path(tmp) / "out"
    out_dir.mkdir()

    with zipfile.ZipFile(zip_path, "w") as zf:
        zf.writestr("a.txt", "A\n")
        zf.writestr("b.txt", "B\n")

    with zipfile.ZipFile(zip_path) as zf:
        zf.extract("a.txt", path=out_dir)
        zf.extractall(path=out_dir)

    print(sorted(p.name for p in out_dir.iterdir()))

extract(member, path=...) pulls one file. extractall(path=...) unpacks every member. Pass a directory to path to control the destination.

Extract only selected members by looping:

python
with zipfile.ZipFile(zip_path) as zf:
    for name in zf.namelist():
        if name.endswith(".txt"):
            zf.extract(name, path=out_dir)
WARNING
Inspect untrusted archives before extraction. Malicious ZIP files can contain path tricks (Zip Slip) that write outside your target folder. Only extract from trusted sources, validate member paths, or use libraries that enforce safe extraction paths.

Handle password-protected ZIP files

The standard zipfile module can read many encrypted ZIP files. Pass the password as bytes to pwd= on extract(), extractall(), read(), or open(), or set a default with setpassword():

python
with zipfile.ZipFile("secret.zip") as zf:
    zf.setpassword(b"my-password")
    data = zf.read("confidential.txt")

Encryption support depends on how the archive was created (classic ZipCrypto vs AES). Unsupported schemes raise RuntimeError or NotImplementedError.

NOTE
The standard zipfile module cannot create encrypted ZIP files. To produce password-protected archives, use another tool (for example zip on the command line) or a third-party library—not ZipFile.write() alone.

Choose compression method and compression level

Constant Meaning
ZIP_STORED No compression—fast, larger files
ZIP_DEFLATED Default choice—DEFLATE compression (widely compatible)
ZIP_BZIP2 BZIP2—often smaller, slower; needs bz2 support
ZIP_LZMA LZMA—strong compression; needs lzma support

Pass compression= when opening in write mode:

python
with zipfile.ZipFile("out.zip", "w", compression=zipfile.ZIP_DEFLATED, compresslevel=6) as zf:
    zf.writestr("data.txt", "payload")

compresslevel (0–9 for ZIP_DEFLATED) trades speed vs size. Use ZIP_STORED when data is already compressed (JPEG, PNG, gzip). Exotic methods may produce archives that older unzip tools cannot read.


Create ZIP files in memory with BytesIO

For web downloads, APIs, or temporary reports, build the archive in memory:

python
import zipfile
from io import BytesIO

buffer = BytesIO()
with zipfile.ZipFile(buffer, "w", zipfile.ZIP_DEFLATED) as zf:
    zf.writestr("report.txt", "Generated content\n")

payload = buffer.getvalue()
print(len(payload))

You should see a byte length greater than zero. Send payload in an HTTP response, or persist it with Path("out.zip").write_bytes(payload)—the same path and mode ideas as write to file in Python.


Work with large ZIP files safely

  • Prefer ZipFile.open(name) over read(name) when members are large—read in chunks or line by line.
  • Keep allowZip64=True (the default) so archives can exceed 4 GB and hold large files.
  • Avoid loading every member into memory at once when processing big archives.
  • Call testzip() to find the first corrupt member (None means no bad CRC detected in the test pass):
python
with zipfile.ZipFile("big.zip") as zf:
    bad = zf.testzip()
    print(bad)

Handle zipfile errors

Exception Typical cause
BadZipFile File is missing, truncated, or not a valid ZIP
LargeZipFile Archive needs ZIP64 but allowZip64=False
KeyError Member name not in the archive (read / getinfo)
RuntimeError / NotImplementedError Unsupported compression or encryption method
FileNotFoundError Archive path does not exist when opening
python
import zipfile
from pathlib import Path

path = Path("not-a-zip.bin")
path.write_bytes(b"not a zip")

try:
    zipfile.ZipFile(path)
except zipfile.BadZipFile:
    print("invalid archive")

Wrap production code in try/except when paths come from users or downloads.


Can you delete a file from a ZIP archive?

There is no delete() method on ZipFile. To remove one member, write a new archive and copy everything except the unwanted entry:

python
import tempfile
import zipfile
from pathlib import Path

def rebuild_without(zip_in: Path, zip_out: Path, skip: str) -> None:
    with zipfile.ZipFile(zip_in, "r") as zin, zipfile.ZipFile(
        zip_out, "w", zipfile.ZIP_DEFLATED
    ) as zout:
        for info in zin.infolist():
            if info.filename == skip:
                continue
            zout.writestr(info, zin.read(info.filename))

with tempfile.TemporaryDirectory() as tmp:
    src = Path(tmp) / "old.zip"
    dst = Path(tmp) / "new.zip"
    with zipfile.ZipFile(src, "w") as zf:
        zf.writestr("keep.txt", "stay")
        zf.writestr("drop.txt", "go")

    rebuild_without(src, dst, "drop.txt")
    with zipfile.ZipFile(dst) as zf:
        print(zf.namelist())

You should see only keep.txt. Replace the original file only after the new archive verifies correctly.


Summary

The Python zipfile module manages .zip archives—separate from built-in zip(). Use ZipFile in 'w' to create (overwriting an existing path), 'a' to append members, and 'r' to read. Common methods: write(), writestr(), namelist(), read(), open(), extract(), and extractall(). Prefer open() for large members; use allowZip64=True for big archives. The module can extract many password-protected ZIPs with pwd= or setpassword() but cannot create encrypted archives. To drop a member, rebuild a new ZIP without that entry.


Frequently Asked Questions

1. What is the difference between zip() and zipfile in Python?

zip() is a built-in that pairs iterables into tuples. zipfile is a standard-library module for creating, reading, and extracting .zip archive files on disk or in memory.

2. Can Python zipfile create password-protected ZIP files?

No—the standard zipfile module can extract many encrypted archives with pwd= or setpassword(), but it cannot create encrypted ZIP files. Use another tool or library to produce password-protected archives.

3. How do I read a file inside a ZIP without extracting everything?

Open the archive with ZipFile, then use read(name) for bytes or open(name) for a file-like object—prefer open() for large members so you do not load the whole file into memory.

4. Can I delete one file from an existing ZIP with zipfile?

There is no delete() API—copy all members except the unwanted one into a new ZipFile in write mode, then replace the old archive.

5. Do I need pip install for zipfile?

No—zipfile is in the Python standard library. Import it with import zipfile or from zipfile import ZipFile.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive …