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.
import tarfile
with tarfile.open("backup.tar.gz", "w:gz") as archive:
archive.add("data.csv")
archive.add("notes.txt")
print("Archive created") # Archive createdtarfile.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.
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")| Mode | Format | Extension |
|---|---|---|
| "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.
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:
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().
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:
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.
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:
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:
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.
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.
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:
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:
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
| Feature | tarfile | zipfile |
|---|---|---|
| Compression | gzip, bzip2, xz (streaming) | Deflate, Bzip2, LZMA (per-file) |
| Preserves permissions | Yes (Unix) | Limited |
| Random access to files | No (sequential) | Yes (index at end) |
| Append to existing | Yes (uncompressed only) | Yes (compressed or not) |
| Cross-platform | Unix-focused, works on all | Universal |
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
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:xzsuffixes control compression. - Use
arcnameto strip unwanted directory prefixes when archiving.
Frequently Asked Questions
Should I use tarfile or zipfile for archiving?
How do I create a .tar.gz archive?
Can I add files to an existing tar archive?
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.
More in this topic
Format Dates and Times in Python
Learn how to use strftime and strptime to format dates as strings and parse date strings into Python datetime objects.
What Is the Python Standard Library?
Learn what the Python standard library is, why it matters, and how to use its built-in modules without installing anything extra.
Encode and Decode Base64 Data in Python
Learn how to use Python's base64 module to encode binary data as text and decode Base64 strings back to bytes.