Hardware FixRecommendedDevice not working? Your driver may be the problemCheck updates for common hardware issues.Fix DriversOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsSlow PC?RecommendedPC slow today? Run a repair scan before it gets worseResolve common Windows issues and optimize system performance.Scan Now×
Skip to content
File size

How to Check File and Folder Sizes in Python

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
from 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.

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():

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Format 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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

Leave a Reply

Your email address will not be published. Required fields are marked *

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Read next

Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
PC Slower Than It Used to Be?Free scan - under a minute

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.