os.stat
st_size is bytes, not characters. Times are float seconds since the epoch (st_mtime) or exact integer nanoseconds (st_mtime_ns). Test the file type with the stat module (stat.S_ISDIR(st.st_mode)). Some fields mean different things per OS — st_ctime is the metadata-change time on Unix.
Demo
import os with open('data.txt', 'wb') as f: f.write('hello'.encode('utf-8')) (os.stat('data.txt').st_size, len('hello'))
'héllo wörld' is 11 characters but 13 bytes, because é and ö take two bytes each in UTF-8, and the emoji takes four. The stat module turns st_mode into answers: S_ISDIR for folders, S_ISREG for regular files; a missing path raises FileNotFoundError. utime stores the time you give it and st_mtime reads it back as a float — use st_mtime_ns when you need exact integers. File systems limit the range: ext4 on Linux, for example, cannot store dates far in the future and clamps them.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| path | str | bytes | PathLike | int | yes | The file to inspect (an open file descriptor also works, like fstat). |
| follow_symlinks | bool | no (True) | False inspects a symlink itself — the same as lstat. |
| times | tuple[float, float] | None | no (None) | utime only: (atime, mtime) in seconds; None means "now". |
| ns | tuple[int, int] | no | utime only: (atime_ns, mtime_ns) in integer nanoseconds. Do not pass both times and ns. |
Return value
os.stat_result — st_mode, st_ino, st_dev, st_nlink, st_uid, st_gid, st_size, st_atime, st_mtime, st_ctime (also by index 0–9), plus *_ns integer times and platform extras. utime returns None.
Common patterns
import os, datetime st = os.stat(path) size_kb = st.st_size / 1024 modified = datetime.datetime.fromtimestamp(st.st_mtime, tz=datetime.timezone.utc)
import os st = os.stat(path) signature = (st.st_size, st.st_mtime_ns) if signature != last_signature: reload()
import os with open(path, 'a'): os.utime(path, None)
import os src = os.stat('original.txt') os.utime('copy.txt', ns=(src.st_atime_ns, src.st_mtime_ns))
Examples
Pitfalls
text = 'naïve café' len(text)
import os text = 'naïve café' with open('t.txt', 'wb') as f: f.write(text.encode('utf-8')) os.stat('t.txt').st_size
ns = 1700000000123456789 int(ns / 1e9 * 1e9) == ns
import os open('f', 'w').close() os.utime('f', ns=(0, 1700000000000000000)) os.stat('f').st_mtime_ns == 1700000000000000000
import os try: os.stat('ghost.txt') state = 'present' except OSError: state = 'missing?' state
import os try: os.stat('ghost.txt') state = 'present' except FileNotFoundError: state = 'missing' state
When to use
- Size, timestamps, type and mode bits of a file in one call
- Setting timestamps (utime), e.g. after copying or for tests
- Only "is it a file / does it exist" → os.path.isfile / exists
- Only the size → os.path.getsize (a stat underneath)
- Copying metadata between files → shutil.copystat / copy2
Notes
FAQ
os.stat(path).st_size, or the shortcut os.path.getsize(path) — both in bytes. Path(path).stat().st_size is the pathlib way.