Reading Filesystem Metadata with os.stat() and stat
Read filesystem metadata safely with os.stat(), pathlib stat methods, stat mode helpers, timestamps, and portable error handling.
Intermediate
Filesystem metadata describes a path as the operating system reports it: its type, size, timestamps, permissions and sometimes identifiers. Python exposes this through os.stat() and Path.stat(); the stat module provides portable helpers for interpreting the mode bits. This lesson teaches how to read that information, not how to build paths (Paths and pathlib), compare file contents (filecmp), or change permissions.
Read metadata for an existing path
os.stat(path) and Path.stat() return a stat result. For a regular file, st_size is its size in bytes. The timestamps describe filesystem events, not a guaranteed timeline with uniform precision. A query may fail with OSError or a subclass such as FileNotFoundError or PermissionError; handle the errors your program can reasonably recover from.
Output
Ready to run.
Interpret file types and permission bits
st_mode combines file-type information and mode/permission bits. Use stat.S_ISREG(), stat.S_ISDIR(), and the other S_IS* helpers to test a type; do not compare the whole st_mode number to a guessed constant. stat.S_IMODE() extracts the permission and special bits that chmod-style modes can represent. Permission bits are not a complete cross-platform access-control model.
Output
Ready to run.
Choose timestamps carefully
st_mtime describes content modification time and st_atime describes access time. st_ctime is platform-dependent: on Unix-like systems it commonly means metadata-change time, while Windows has historically used it for creation time and now exposes creation time through st_birthtime on supported versions. Never treat ctime as a portable creation timestamp. Nanosecond-named fields are integers, but the underlying filesystem may record time at coarser resolution.
Output
Ready to run.
Compare stat, lstat, and fstat
os.stat() and Path.stat() follow a symbolic link by default, so their result describes the target. os.lstat() (or Path.lstat()) describes the link itself. os.fstat() obtains metadata for an already-open file descriptor. These choices answer different questions; do not assume a path checked earlier will still refer to the same object when opened later.
Output
Ready to run.
Output
Ready to run.
Expect filesystem errors
A failed metadata query raises an exception instead of returning an ordinary stat result. Catch FileNotFoundError when a missing path is an expected case; use OSError for a broader filesystem failure boundary and preserve unexpected failures when your program cannot recover. A separate access check is not a guarantee that a later operation will succeed, because permissions and the filesystem can change between operations.
Output
Ready to run.
Know which metadata is portable
st_size and modification timestamps are useful for ordinary files, but their meaning depends on the object type and filesystem. st_ino and st_dev can help identify an object on some systems, but their values are not globally unique, persistent IDs across filesystems, or portable application identifiers. Optional attributes such as st_birthtime and platform-specific flags may not exist everywhere; use getattr() or hasattr() when their absence is legitimate.
Output
Ready to run.
Use metadata without promising too much
A stat result is a snapshot returned by one query. It can become stale immediately and usually should not be used as a security boundary before opening, deleting, or changing a path. Prefer attempting the intended operation and handling its error. For content integrity, compare bytes or use a cryptographic digest; matching size and timestamps alone is not proof that files are identical.
Read the byte size
Which field reports the number of bytes for a regular file?
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as temporary:
path = Path(temporary) / "memo.txt"
path.write_bytes(b"abc")
size = path.stat().
assert size == 3
print(size)
Recognize a regular file
Choose the stat helper that checks file type.
import stat
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as temporary:
path = Path(temporary) / "memo.txt"
path.write_text("x", encoding="utf-8")
is_regular = stat.(path.stat().st_mode)
assert is_regular
print(is_regular)
Inspect the link itself
Use the stat call that reports metadata without following a symbolic link.
import os
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as temporary:
path = Path(temporary) / "possible-link.txt"
path.write_text("x", encoding="utf-8")
info = os.(path)
assert info.st_size == 1
print("metadata read")
Read the modification timestamp
Choose the integer nanosecond modification field.
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as temporary:
path = Path(temporary) / "record.txt"
path.write_text("record", encoding="utf-8")
info = path.stat()
modified = info.
assert isinstance(modified, int)
print("nanosecond field used")
Handle a missing path
Use the specific exception for a path that does not exist.
import os
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as temporary:
missing = Path(temporary) / "missing-file.txt"
try:
os.stat(missing)
except as error:
print(type(error).__name__)
Thanks for your feedback.
Mark this learning resource complete to track your learning progress.