Skip to content
Foxipa

Suggest an edit

Tell us what should be corrected, clarified, or improved. Submission will be connected to Foxipa’s contribution service later.

No information is sent anywhere yet. Your suggestion is only prepared in your browser.

Learning

Working with ZIP Archives Using zipfile

Create, inspect, update, verify, and selectively extract ZIP archives with Python’s standard-library zipfile module.

Levels: Intermediate ~35 min read

Intermediate

Python’s zipfile module lets you create, inspect, read, update, and extract ZIP archives. It works below the higher-level archive helpers in shutil: use zipfile when you need to decide which members to write, inspect individual entries, or read a member without first extracting the whole archive.

Choose between zipfile and shutil

shutil.make_archive() and shutil.unpack_archive() are convenient for common whole-directory archive tasks. ZipFile gives finer control over archive modes, member names, compression choices, member metadata, and reading individual members. A ZIP archive is not the same thing as a compressed single file: it is a container with its own member list and metadata.

Create a ZIP archive with member names

Open ZipFile in write mode and add content with writestr() when you already have the content in memory. Each name is stored inside the archive; it does not have to be a path on the current filesystem. Use a with statement so the ZIP directory and other final records are written when the archive closes.

Interactive Runnable example
Edit

Ready to run.

Write files with archive-relative names

ZipFile.write() copies an existing filesystem file into an archive. Its arcname argument controls the name stored in the archive, which is usually better than preserving a machine-specific absolute path. Prefer short relative names that make sense to someone opening the archive on another computer.

Interactive Runnable example
Edit

Ready to run.

Inspect archive members

namelist() returns the stored member names. infolist() returns ZipInfo objects with details such as each member’s name, uncompressed size, and compression method. A ZIP file may contain duplicate member names; when that matters, keep and pass the specific ZipInfo object rather than assuming a name identifies exactly one entry.

Interactive Runnable example
Edit

Ready to run.

Read member bytes and decode text

ZipFile.read() returns bytes, not str. Decode those bytes using the encoding that was used for the text, just as you would when reading a binary file. For larger members, ZipFile.open() provides a file-like stream so the whole decompressed member does not need to be loaded into memory at once.

Interactive Runnable example
Edit

Ready to run.

Append to an archive and check its integrity

Use mode "a" to add members to an existing ZIP archive. It preserves existing members and appends new entries. testzip() reads members and checks their headers and CRC values, returning the first bad member name or None. This check detects some corruption; it does not establish that an archive is safe or trustworthy.

Interactive Runnable example
Edit

Ready to run.

Extract archives only when you trust the source

Use extract() or extractall() only after considering where the members will be written and how much data they may expand to. zipfile attempts to sanitize some dangerous member paths, but untrusted ZIP files can still overwrite files or exhaust disk space and memory. Inspect names and sizes first, extract into a new controlled directory, and enforce application-specific limits. Unlike tarfile, ZIP extraction has no tar extraction-filter parameter.

Interactive Runnable example
Edit

Ready to run.

Choose compression deliberately. ZIP_STORED stores members without compression; ZIP_DEFLATED is broadly supported but needs zlib. Other compression methods may not be available in every Python installation or supported by every archive tool. This lesson uses ZIP_STORED and ZIP_DEFLATED so its examples run in the available local interpreter.

Quick check

Which method adds an in-memory string or bytes value under a chosen member name?

from pathlib import Path
from tempfile import TemporaryDirectory
from zipfile import ZipFile

with TemporaryDirectory() as folder:
    archive_path = Path(folder) / "notes.zip"
    with ZipFile(archive_path, "w") as archive:
        
    with ZipFile(archive_path) as archive:
        assert archive.read("notes.txt") == b"ready"
    print("written")

Quick check

Which argument stores a portable member name rather than the original filesystem path?

from pathlib import Path
from tempfile import TemporaryDirectory
from zipfile import ZipFile

with TemporaryDirectory() as folder:
    root = Path(folder)
    source = root / "input.csv"
    source.write_text("id\n1\n", encoding="utf-8")
    with ZipFile(root / "data.zip", "w") as archive:
        
    with ZipFile(root / "data.zip") as archive:
        assert archive.namelist() == ["tables/input.csv"]
    print("portable member path")

Quick check

ZipFile.read() returns bytes. Which operation converts UTF-8 bytes into a Python string?

from pathlib import Path
from tempfile import TemporaryDirectory
from zipfile import ZipFile

with TemporaryDirectory() as folder:
    path = Path(folder) / "message.zip"
    with ZipFile(path, "w") as archive:
        archive.writestr("message.txt", "Hi")
    with ZipFile(path) as archive:
        message = 
        assert message == "Hi"
    print(message)

Quick check

What does testzip() returning None tell you?

from pathlib import Path
from tempfile import TemporaryDirectory
from zipfile import ZipFile

with TemporaryDirectory() as folder:
    path = Path(folder) / "bundle.zip"
    with ZipFile(path, "w") as archive:
        archive.writestr("one.txt", "1")
    with ZipFile(path) as archive:
        
        assert result is None
    print("member checks finished")

Quick check

The example archive was created by your own program. Which destination choice keeps extracted files separate from the archive and working files?

from pathlib import Path
from tempfile import TemporaryDirectory
from zipfile import ZipFile

with TemporaryDirectory() as folder:
    root = Path(folder)
    path = root / "bundle.zip"
    with ZipFile(path, "w") as archive:
        archive.writestr("docs/readme.txt", "hello")
    destination = root / "unpacked"
    destination.mkdir()
    with ZipFile(path) as archive:
        
    assert (destination / "docs" / "readme.txt").read_text(encoding="utf-8") == "hello"
    print("extracted to isolated directory")

Key takeaways

  • Use ZipFile when an application needs control over individual ZIP members; use shutil for simpler whole-archive workflows.
  • Use write() for an existing file and writestr() for content already in memory. Choose archive-relative member names.
  • ZIP member reads return bytes. Decode text explicitly and use open() when you need file-like access to a member.
  • testzip() checks member headers and CRCs; it does not prove a ZIP is trusted or safe to extract.
  • Inspect untrusted archive names and sizes, use a dedicated extraction directory, and apply limits before writing content to disk.

Keep practising

Practise with the ZIP archive code-completion challenges and the ZIP archive quiz . For current parameters, compression support, and extraction warnings, consult the official Python 3.15 zipfile reference, particularly the sections on decompression pitfalls .

Was this page helpful?

Mark this learning resource complete to track your learning progress.