The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Use os.path.getsize() or Path.stat().st_size to read one file’s logical size in bytes. To measure a folder’s contents, walk its descendants and add each file’s size. The examples below cover modern pathlib, os.walk, os.scandir, symlink policies, errors, sparse files, display units, and filesystem capacity.
Check the size of one file
Python reports file sizes as integer bytes. The value is the file’s logical st_size, not a human-formatted number and not necessarily the number of disk blocks allocated.
Using os.path.getsize
import os
size_bytes = os.path.getsize("report.pdf")
print(size_bytes)
os.path.getsize(path) returns the size, in bytes, of the specified path. A missing or inaccessible path raises OSError. The Python documentation describes it as: “Return the size, in bytes, of path.”
Using pathlib
from pathlib import Path
size_bytes = Path("report.pdf").stat().st_size
print(size_bytes)
Path.stat() returns an os.stat_result; its st_size field is the byte count for a regular file. pathlib is often more convenient when the rest of your program already uses Path objects. See the Path.stat documentation.
#1 Best Overall
Handle a single-path failure explicitly
from pathlib import Path
path = Path("report.pdf")
try:
print(path.stat().st_size)
except FileNotFoundError:
print(f"Not found: {path}")
except PermissionError:
print(f"Permission denied: {path}")
For broader handling, catch OSError. Do not silently turn an operational error into a zero-byte result unless that is an intentional policy.
Calculate a folder’s total size recursively
A directory entry does not contain the sum of everything beneath it. To obtain a content total, traverse descendant directories and add the sizes of files you encounter. The result is a traversal-time snapshot: files can be created, removed, or changed while the walk runs.
os.walk: portable and clear
import os
def folder_size(path: str) -> int:
total = 0
for root, dirs, files in os.walk(path):
for name in files:
try:
total += os.path.getsize(os.path.join(root, name))
except OSError:
# Log, skip, or re-raise according to your application.
pass
return total
print(folder_size("project"))
os.walk uses os.scandir internally. The function above counts files yielded by the walk and skips paths that cannot be statted. For backups, audits, or compliance reports, replace pass with logging or re-raise the exception so skipped data is visible.
Path.walk: Python 3.12 and newer
from pathlib import Path
def folder_size(path: Path) -> int:
total = 0
for root, dirs, files in path.walk():
total += sum((root / name).stat().st_size for name in files)
return total
print(folder_size(Path("project")))
Path.walk() requires Python 3.12 or newer. It exposes mutable dirs, allowing you to prune directories before traversal continues:
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Fix the driver behind crashes, sound loss and screen glitches3Clear out junk files and repair common Windows errorsfrom pathlib import Path
def source_size(path: Path) -> int:
total = 0
for root, dirs, files in path.walk():
dirs[:] = [name for name in dirs if name != "__pycache__"]
for name in files:
try:
total += (root / name).stat().st_size
except OSError:
pass
return total
os.scandir when entry metadata matters
import os
def folder_size(path: str) -> int:
total = 0
for root, dirs, files in os.walk(path):
with os.scandir(root) as entries:
for entry in entries:
if entry.is_file(follow_symlinks=False):
try:
total += entry.stat(follow_symlinks=False).st_size
except OSError:
pass
return total
DirEntry.is_file() and DirEntry.stat() can reduce repeated path parsing and let you state symlink behavior directly. The PEP 471 specification documents these directory-entry operations and their possible OSError failures.
Rank #2
Choose a symlink policy deliberately
Symlinks can make a “folder size” mean different things. By default, os.walk does not descend into symlinked directories. Setting followlinks=True can follow a link back to an ancestor and recurse forever; use it only with cycle protection and a clearly defined policy.
Count regular files without following file symlinks
The os.scandir example uses entry.is_file(follow_symlinks=False) and entry.stat(follow_symlinks=False). A symlink to a file is therefore excluded.
Measure the target of a symlink
Path.stat() follows symlinks. To inspect the link object itself, use Path.lstat():
from pathlib import Path
link = Path("latest-report")
target_bytes = link.stat().st_size
link_object_bytes = link.lstat().st_size
These values answer different questions. The first measures the target; the second measures the symlink entry.
Following directory links safely
If your application must include linked directories, maintain a set of visited directory identities (typically device and inode from stat()) and refuse to revisit an identity. Also decide whether a file reachable through multiple paths should be counted once or once per path.
Logical bytes versus allocated disk space
st_size is logical content length. Sparse files may report a large logical size while occupying fewer filesystem blocks; compression or deduplication can also make allocated storage differ from logical bytes. A recursive sum of st_size is therefore appropriate for content totals, upload limits, and byte-level comparisons, but not for answering “how full is this disk?”
Check filesystem capacity instead
import shutil
usage = shutil.disk_usage("project")
print(f"total={usage.total} bytes")
print(f"used={usage.used} bytes")
print(f"free={usage.free} bytes")
shutil.disk_usage(path) returns named fields total, used, and free, all in bytes, for the filesystem containing the path. It does not calculate the content total of that directory. See the shutil documentation.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Format bytes for people, keep integers for logic
Convert only at the presentation boundary. Keep integer bytes for limits, sorting, billing, and tests so rounding cannot change a decision.
def human_bytes(n: int) -> str:
units = ["B", "KiB", "MiB", "GiB", "TiB"]
value = float(n)
for unit in units:
if value < 1024 or unit == units[-1]:
return f"{value:.1f} {unit}"
value /= 1024
print(human_bytes(1536)) # 1.5 KiB
This uses binary units (1 KiB = 1,024 bytes). If your interface promises decimal units, use 1,000-byte steps and label them kB, MB, and GB instead.
Build a production-ready folder counter
The following version exposes an explicit error policy and returns both the total and skipped paths. It does not follow directory symlinks and does not count file symlinks.
from pathlib import Path
from typing import Iterable
def folder_size(path: Path) -> tuple[int, list[tuple[Path, OSError]]]:
total = 0
errors: list[tuple[Path, OSError]] = []
for root, dirs, files in path.walk():
# Do not descend through directory symlinks.
dirs[:] = [name for name in dirs if not (root / name).is_symlink()]
for name in files:
file_path = root / name
try:
if file_path.is_file() and not file_path.is_symlink():
total += file_path.stat().st_size
except OSError as exc:
errors.append((file_path, exc))
return total, errors
size, errors = folder_size(Path("project"))
print(f"{size} bytes")
for file_path, error in errors:
print(f"Skipped {file_path}: {error}")
For a fail-fast tool, raise the first exception instead. For an interactive report, retaining skipped paths makes the result auditable rather than silently incomplete.
Troubleshoot incorrect or surprising results
The directory itself reports only a few bytes
Path("folder").stat().st_size measures the directory entry, not its descendants. Walk the tree and sum file sizes.
The total changes between runs
A walk is not transactional. Editors, downloads, build processes, and log rotation can modify files during traversal. Run against a quiescent directory, or accept and document snapshot variability.
A file disappears or access is denied
getsize, Path.stat, and DirEntry.stat raise OSError when a path vanishes or permissions change. Choose fail-fast, skip-with-log, or return-an-error-list behavior.
A symlink causes a huge total or a loop
Check whether your code follows links. Keep the default non-following behavior unless linked targets are required; if links must be followed, add visited-directory cycle detection.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Best Value
The number does not match “space used” in the operating system
You are comparing logical bytes with allocated blocks, compression, or sparse-file accounting. Use shutil.disk_usage for filesystem capacity, and treat its result as a filesystem-level measurement rather than a directory-content total.
Python rejects Path.walk()
Path.walk is available in Python 3.12+. On older supported versions, use os.walk or upgrade the interpreter.
Or skip the browser setup:
If your workflow also needs screenshots of a file-size report, documentation page, or dashboard, ScreenshotNeo provides a website screenshot API and MCP server. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing result.
One GET request returns PNG, JPEG, WebP, or PDF. The service also supports full-page captures with lazy images, CSS-selector element capture, dark mode, device presets, arbitrary viewports, retina scale, PDF paper and page options, custom CSS and JavaScript, pre-capture clicks, hidden selectors, selector/delay/network-idle waits, request and resource blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed image links, asynchronous webhooks, bulk capture of up to 100 URLs per call, a usage API, and an OpenAPI specification.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo documentation for parameters and response details. An MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Sign up free for ScreenshotNeo.
Frequently Asked Questions
Should I use decimal or binary units when displaying a result?
Choose one convention for your interface and label it. The example uses binary KiB, MiB, and GiB; retain the original integer byte count internally.
Can a folder-size total be perfectly consistent while files are changing?
No. Standard directory walks are traversal-time snapshots, so concurrent writes, deletes, and renames can affect the result.
What should my program do when one file cannot be read?
Select a deliberate policy: fail immediately, skip while logging the path and exception, or return the total together with a list of skipped paths.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




