Archive Files with Python `tarfile`

Learn how to use Python's tarfile module to create, extract, and inspect tar archives with gzip and bzip2 compression.

7 min read

The tarfile module in the Python standard library creates, reads, and extracts tar archives, including those compressed with gzip (.tar.gz), bzip2 (.tar.bz2), and xz (.tar.xz). Tar is the standard archive format on Unix and Linux systems, commonly used for software distribution, backups, and long-term storage.

pythonpython
import tarfile
 
with tarfile.open("backup.tar.gz", "w:gz") as archive:
    archive.add("data.csv")
    archive.add("notes.txt")
 
print("Archive created")  # Archive created

tarfile.open("backup.tar.gz", "w:gz") creates a new gzip-compressed tar archive. The :gz suffix adds compression. archive.add("data.csv") adds that file to the archive.

Creating tar archives

Unlike zipfile, tarfile bakes the compression choice directly into the mode string you pass when opening the archive. The mode string controls compression. The w means write, and the suffix after : specifies the compression method.

pythonpython
import tarfile
 
files = ["data.csv", "notes.txt", "config.json"]
 
with tarfile.open("project.tar.gz", "w:gz") as archive:
    for filename in files:
        archive.add(filename)
    print("Archive created with gzip compression")
ModeFormatExtension
"w"Uncompressed tar.tar
"w:gz"Gzip compressed.tar.gz or .tgz
"w:bz2"Bzip2 compressed.tar.bz2
"w:xz"XZ/LZMA compressed.tar.xz

Gzip is fast and widely compatible. Bzip2 typically produces smaller archives but is slower. XZ gives the best compression ratio but is the slowest.

Adding directories

archive.add() on a directory recursively includes all files and subdirectories.

pythonpython
import tarfile
 
with tarfile.open("full_backup.tar.gz", "w:gz") as archive:
    archive.add("project_src", arcname="src")
    archive.add("docs", arcname="documentation")

The arcname parameter renames the top-level directory inside the archive. Without it, files are stored under project_src/...; with arcname="src", they are under src/....

To exclude certain files, use a filter function:

pythonpython
import tarfile
 
def exclude_cache(tarinfo):
    if "__pycache__" in tarinfo.name or tarinfo.name.endswith(".pyc"):
        return None
    return tarinfo
 
with tarfile.open("clean_backup.tar.gz", "w:gz") as archive:
    archive.add("project", filter=exclude_cache)

The filter receives each TarInfo object before it is added. Return None to skip the entry, or return the (possibly modified) TarInfo to include it.

Listing archive contents

Open in read mode and use .getnames() or .getmembers().

pythonpython
import tarfile
 
with tarfile.open("backup.tar.gz", "r:gz") as archive:
    for member in archive.getmembers():
        kind = "dir" if member.isdir() else "file"
        size = member.size if member.isfile() else 0
        print(f"{kind:5} {size:>8}  {member.name}")

The loop prints each member's kind and size side by side, giving a quick directory-style listing without extracting anything to disk first:

texttext
file      1250  data.csv
file      3400  notes.txt
file       210  config.json

.getnames() returns only names. .getmembers() returns TarInfo objects with name, size, type (file, directory, symlink), permissions, and modification time.

Extracting files

Extract all files or individual files from a tar archive.

pythonpython
import tarfile
 
with tarfile.open("backup.tar.gz", "r:gz") as archive:
    archive.extractall(path="restored")
    print("Extracted to 'restored/'")

.extractall(path) extracts everything to the given directory. The directory is created if it does not exist.

To extract a single file:

pythonpython
with tarfile.open("backup.tar.gz", "r:gz") as archive:
    archive.extract("data.csv", path="output")

To read one member's content without writing anything to disk at all, look it up by name and read from the file-like object it returns:

pythonpython
with tarfile.open("backup.tar.gz", "r:gz") as archive:
    member = archive.getmember("config.json")
    content = archive.extractfile(member).read()
    print(content.decode())

.extractfile(member) returns a file-like object for reading the member's content without writing to disk.

Adding data from memory

Use tarfile.TarInfo and addfile() to add string or byte data directly.

pythonpython
import tarfile
from io import BytesIO
from datetime import datetime
 
content = f"Backup generated: {datetime.now()}\n".encode()
 
with tarfile.open("report.tar.gz", "w:gz") as archive:
    info = tarfile.TarInfo(name="report.txt")
    info.size = len(content)
    archive.addfile(info, BytesIO(content))

Create a TarInfo object with the desired filename and size, then pass it and a file-like object containing the data to addfile().

Practical example: timestamped backup

Create a compressed backup with a timestamp in the filename.

pythonpython
import tarfile
from pathlib import Path
from datetime import datetime
 
def create_backup(source_dir, backup_dir="backups"):
    source = Path(source_dir)
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    backup_name = Path(backup_dir) / f"{source.name}_{timestamp}.tar.gz"
    backup_name.parent.mkdir(exist_ok=True)
    with tarfile.open(backup_name, "w:gz") as archive:
        archive.add(source, arcname=source.name)
    size_mb = backup_name.stat().st_size / (1024 * 1024)
    print(f"Backup: {backup_name.name} ({size_mb:.1f} MB)")

Calling the function with just the source directory compresses it and reports the resulting archive size once the write finishes:

pythonpython
create_backup("project_src")

The timestamp in the filename guarantees each run produces a distinct archive, so nothing gets overwritten if you back up the same project again later the same day:

texttext
Backup: project_src_20260712_143005.tar.gz (2.3 MB)

The backup name includes the source directory name and the current timestamp. The archive is stored in a backups/ subdirectory.

tarfile vs zipfile

Featuretarfilezipfile
Compressiongzip, bzip2, xz (streaming)Deflate, Bzip2, LZMA (per-file)
Preserves permissionsYes (Unix)Limited
Random access to filesNo (sequential)Yes (index at end)
Append to existingYes (uncompressed only)Yes (compressed or not)
Cross-platformUnix-focused, works on allUniversal

Use tarfile when you need gzip/bzip2 compression, preserve Unix permissions, or work in Linux/macOS environments. Use zipfile when you need per-file random access or maximum cross-platform compatibility.

Common mistakes

Using the wrong mode string. "w:gz" creates gzip-compressed tar. "w" creates uncompressed tar. "r" auto-detects compression.

Forgetting the :gz suffix produces a plain .tar file that is not compressed, even if the filename ends in .tar.gz.

Adding the same file under the wrong arcname. When archiving a directory, archive.add("project/") stores everything under project/... inside the archive. Use arcname to control the stored path and avoid deep, hardcoded directory prefixes.

Extracting without safety checks. Like ZIP files, tar archives can contain paths with .. that extract outside the target directory. Use extractall with a controlled path and consider inspecting member.name before extracting from untrusted archives.

Writing to a compressed tar in append mode. tarfile.open(name, 'a') only works for uncompressed archives. You cannot append to a compressed .tar.gz because the compression stream would need to be rewritten.

Rune AI

Rune AI

Key Insights

  • Use tarfile.open(name, 'w:gz') to create a gzip-compressed tar archive.
  • Use .add(path, arcname=...) to add files and directories to an archive.
  • Use .extractall(path) to extract an entire archive.
  • Use .getnames() and .getmembers() to inspect archive contents.
  • The :gz, :bz2, and :xz suffixes control compression.
  • Use arcname to strip unwanted directory prefixes when archiving.
RunePowered by Rune AI

Frequently Asked Questions

Should I use tarfile or zipfile for archiving?

Use `tarfile` when you need gzip or bzip2 compression, when you are working in Unix/Linux environments, or when you need to preserve Unix file permissions and ownership. Use `zipfile` when you need cross-platform compatibility with Windows users or when you need individual file access without decompressing the entire archive.

How do I create a .tar.gz archive?

Open the archive with `tarfile.open(name, 'w:gz')`. The `:gz` suffix adds gzip compression. For bzip2, use `'w:bz2'`. For xz, use `'w:xz'`. For no compression (plain .tar), use `'w'`.

Can I add files to an existing tar archive?

Yes. Open the archive in append mode with `tarfile.open(name, 'a')`. This works for uncompressed tar files. Appending to compressed archives is not supported because the compression stream cannot be partially rewritten.

Conclusion

The tarfile module is the standard way to work with tar archives in Python. Use it to bundle directories, create compressed backups with gzip or bzip2, and extract software distributions. Use 'w:gz' for the common .tar.gz format and TarFile.add() with arcname to control paths inside the archive.