Working with TAR Archives Using tarfile
Create, inspect, read, compress, and cautiously extract TAR archives with Python’s standard-library tarfile module.
Intermediate
Python’s tarfile module reads and writes TAR archives. Unlike a ZIP archive, a TAR archive is fundamentally a sequence of filesystem entries; compression is a separate choice such as gzip or xz. Use tarfile when you need direct control over archive members, metadata, streaming, or extraction filters. Use shutil for simpler whole-directory archive workflows, and zipfile for ZIP members.
Choose a TAR mode and compression method
The first part of a mode describes the operation: “r” reads, “w” creates or replaces, “x” creates only if the path does not already exist, and “a” appends. Add a compression suffix such as “:gz” or “:xz” when creating a compressed TAR archive. “r:*” reads a supported TAR archive and detects its compression. Appending is supported only for uncompressed TAR files; modes such as “a:gz” are not valid.
Output
Ready to run.
Add in-memory content with TarInfo and addfile
When the content already exists as bytes instead of a filesystem file, create a TarInfo entry, set its size to the byte count, and pass a binary file-like object to addfile(). This avoids writing a temporary source file first. The member name is still the name stored inside the archive, not a destination path on the current computer.
Output
Ready to run.
Create a compressed TAR archive
A mode like “w:gz” creates a gzip-compressed TAR archive. Compression happens around the TAR stream; it does not turn the archive into a ZIP file. tarfile.open(path, “r:*”) transparently reads supported compressed and uncompressed TAR formats. Python 3.14 added optional Zstandard support through compression.zstd; the local examples below intentionally use gzip because it is available in Python 3.13 as well.
Output
Ready to run.
Inspect TarInfo members
getmembers() returns TarInfo objects in archive order. Each member exposes information such as name, size, and file type. Check isfile(), isdir(), or issym() before treating an entry as a regular file: TAR archives can represent directories and links as well as file content. An archive can also contain more than one entry with the same name.
Output
Ready to run.
Read a member without extracting the archive
extractfile() returns a binary file-like object for a regular file or supported link, or None for directory entries. Read and decode the returned bytes using the encoding of the stored text. This lets you inspect a single member without writing the entire archive to disk, but still treat the archive and its declared sizes as untrusted input.
Output
Ready to run.
Extract into a controlled directory with a data filter
When extracting archives that are not fully trusted, inspect them first and pass filter="data" explicitly where supported. The data filter rejects many risky paths, links, and special files. It is not a complete security guarantee: an archive can still exhaust disk, memory, or CPU, and the destination can be affected by filesystem races. Prefer a new temporary destination and impose application-specific limits. The default filter changed in Python 3.14, so explicit selection makes the intended policy clear on supported versions. Python 3.15 further normalizes names containing `..` in the built-in tar filter and link targets containing `..` in the data filter; older runtimes may behave differently, so do not treat version-specific normalization as a substitute for inspecting members.
Output
Ready to run.
Understand why the extraction filter matters
A TAR member name such as “../outside.txt” attempts to escape its intended destination. Do not hand untrusted archives to fully_trusted extraction, and do not assume a filter eliminates every risk. The following example creates a harmless test archive containing a traversal-style name and verifies that the data filter rejects it without creating the outside file. For real untrusted archives, inspect members before extraction and consider limits on member count, per-file size, total expanded size, and accepted names.
Output
Ready to run.
Keep practising
Store a file under a portable member name
Which expression adds the existing file under the desired archive-relative name?
from pathlib import Path
from tempfile import TemporaryDirectory
import tarfile
with TemporaryDirectory() as folder:
root = Path(folder)
source = root / "today.txt"
source.write_text("Today", encoding="utf-8")
archive_path = root / "today.tar"
with tarfile.open(archive_path, "w") as archive:
with tarfile.open(archive_path) as archive:
assert archive.getnames() == ["reports/today.txt"]
print("portable member name stored")
Choose gzip compression
Which mode creates a gzip-compressed TAR archive?
from pathlib import Path
from tempfile import TemporaryDirectory
import tarfile
with TemporaryDirectory() as folder:
root = Path(folder)
source = root / "notes.txt"
source.write_text("Notes", encoding="utf-8")
archive_path = root / "notes.tar.gz"
with tarfile.open(archive_path, ) as archive:
archive.add(source, arcname="notes.txt")
with tarfile.open(archive_path, "r:*") as archive:
assert archive.getnames() == ["notes.txt"]
print("gzip TAR read")
Inspect member size
Which object provides the name, size, and isfile() method for one archive member?
from pathlib import Path
from tempfile import TemporaryDirectory
import tarfile
with TemporaryDirectory() as folder:
root = Path(folder)
source = root / "brief.txt"
source.write_text("Short brief", encoding="utf-8")
archive_path = root / "brief.tar"
with tarfile.open(archive_path, "w") as archive:
archive.add(source, arcname="brief.txt")
with tarfile.open(archive_path) as archive:
member = archive.getmembers()[0]
print(member.)
assert member.size == len("Short brief")
print("metadata checked")
Read without extracting
Which method opens a single member for reading without extracting it to a filesystem path?
from pathlib import Path
from tempfile import TemporaryDirectory
import tarfile
with TemporaryDirectory() as folder:
root = Path(folder)
source = root / "notes.txt"
source.write_text("Archive note", encoding="utf-8")
archive_path = root / "notes.tar"
with tarfile.open(archive_path, "w") as archive:
archive.add(source, arcname="notes.txt")
with tarfile.open(archive_path) as archive:
with archive.("notes.txt") as stream:
contents = stream.read()
assert contents == b"Archive note"
print("read without extraction")
Apply the data extraction filter
Which argument selects the data extraction policy explicitly?
from pathlib import Path
from tempfile import TemporaryDirectory
import tarfile
with TemporaryDirectory() as folder:
root = Path(folder)
source = root / "notes.txt"
source.write_text("Safe note", encoding="utf-8")
archive_path = root / "notes.tar"
with tarfile.open(archive_path, "w") as archive:
archive.add(source, arcname="notes.txt")
destination = root / "out"
destination.mkdir()
with tarfile.open(archive_path) as archive:
archive.extractall(path=destination, )
assert (destination / "notes.txt").read_text(encoding="utf-8") == "Safe note"
print("controlled extraction complete")
Thanks for your feedback.
Mark this learning resource complete to track your learning progress.