}

Python: Check if File or Directory Exists — os.path, pathlib, try/except (2026)

Python: Check if File or Directory Exists

The quickest way to check if a file exists in Python is os.path.exists(path) — it returns True if the path exists (file or directory) and False otherwise. For modern Python 3.4+ code, Path("file.txt").exists() from pathlib is the preferred approach.

This guide covers every reliable method, when to use each one, and the common mistakes developers make.


Quick Answer

import os

if os.path.exists("file.txt"):
    print("File exists")
else:
    print("File does not exist")

Or with pathlib (Python 3.4+):

from pathlib import Path

if Path("file.txt").exists():
    print("File exists")

Method 1: os.path.exists()

os.path.exists(path) returns True if the path refers to an existing file or directory. It returns False for broken symbolic links.

import os

path = "/tmp/data.csv"

if os.path.exists(path):
    print(f"{path} exists")
else:
    print(f"{path} does not exist")

When to use it: When you need a quick existence check and you don't care whether the path is a file or a directory.

Caveat — race conditions: A gap exists between the time you check and the time you use the file (TOCTOU — Time Of Check To Time Of Use). Another process could delete the file between the exists() call and your open() call. For race-safe file access, use the try/except pattern described in Method 5.


Method 2: os.path.isfile()

os.path.isfile(path) returns True only if the path is an existing regular file — not a directory, socket, or device.

import os

path = "report.txt"

if os.path.isfile(path):
    print("It's a file — safe to open")
else:
    print("Not a file (might be a directory, or doesn't exist)")

When to use it: When you specifically need to confirm you have a regular file before reading or writing it. Using isfile() instead of exists() prevents accidentally treating a directory as a readable file.


Method 3: os.path.isdir()

os.path.isdir(path) returns True only if the path is an existing directory.

import os

path = "/home/user/documents"

if os.path.isdir(path):
    print("Directory exists")
else:
    print("Not a directory (might be a file, or doesn't exist)")

When to use it: Before creating files inside a directory, or when validating that a configuration path points to a directory rather than a file.

import os

output_dir = "results"

if not os.path.isdir(output_dir):
    os.makedirs(output_dir)

Method 4: pathlib Path.exists(), is_file(), is_dir()

pathlib was introduced in Python 3.4 and is now the recommended way to work with filesystem paths. It provides an object-oriented interface that is more readable and cross-platform than string-based os.path calls.

Path.exists()

from pathlib import Path

p = Path("config.json")

if p.exists():
    print("Path exists")

Path.is_file()

from pathlib import Path

p = Path("config.json")

if p.is_file():
    print("It's a regular file")

Path.is_dir()

from pathlib import Path

p = Path("/var/log")

if p.is_dir():
    print("It's a directory")

Combining pathlib with file reading

from pathlib import Path

config_path = Path("settings") / "config.json"

if config_path.is_file():
    content = config_path.read_text(encoding="utf-8")
    print(content)
else:
    print("Config file not found")

The / operator on Path objects builds paths safely across operating systems — no need to worry about forward vs. back slashes.

When to use it: New projects and any code targeting Python 3.4+. pathlib is cleaner, more expressive, and handles path joining and manipulation better than os.path.


Method 5: try/except FileNotFoundError

Python's EAFP principle — Easier to Ask Forgiveness than Permission — says it is often better to attempt an operation and handle the exception than to check for a condition first. For file access, this approach is also race-condition safe.

try:
    with open("data.txt", "r") as f:
        content = f.read()
        print(content)
except FileNotFoundError:
    print("File not found")
except PermissionError:
    print("Permission denied")

Why this is race-safe: You never check separately — you just try to open the file. If it disappears between a check and an open, you still get a clean exception rather than a crash or undefined behaviour.

Catching OSError for broader coverage:

try:
    with open("data.txt", "r") as f:
        content = f.read()
except OSError as e:
    print(f"Could not read file: {e}")

FileNotFoundError is a subclass of OSError, so catching OSError also handles permission errors and other I/O failures in one block.

When to use it: Whenever you are going to open and use the file immediately after checking — which is almost always. This is the most Pythonic pattern.


Comparison Table

MethodChecksFilesDirsRace-safePython version
os.path.exists()File or directoryYesYesNo2.x+
os.path.isfile()Files onlyYesNoNo2.x+
os.path.isdir()Directories onlyNoYesNo2.x+
Path.exists()File or directoryYesYesNo3.4+
Path.is_file()Files onlyYesNoNo3.4+
Path.is_dir()Directories onlyNoYesNo3.4+
try/except FileNotFoundErrorFile (at open time)YesNoYes2.x+

When to Use Which

Use os.path.exists() when you need a simple existence check and the result won't be immediately followed by file I/O. Example: validating user input before queuing a background job.

Use os.path.isfile() when you must confirm the path is a regular file — not a directory — before processing it. Example: checking a log file path before rotating it.

Use os.path.isdir() when you need to confirm a directory exists before writing output files into it.

Use pathlib for all new Python 3 code. It is cleaner, supports the / operator for path joining, and has equivalent exists(), is_file(), and is_dir() methods.

Use try/except FileNotFoundError whenever you are going to open the file right after checking. This is the safest and most Pythonic pattern — it eliminates the race window and handles the error in one place.


Common Mistakes

Mistake 1: Using exists() when you mean isfile()

# Risky — path could be a directory, not a file
if os.path.exists("output"):
    with open("output", "r") as f:  # IsADirectoryError if "output" is a dir
        data = f.read()

# Better — confirm it is actually a file
if os.path.isfile("output"):
    with open("output", "r") as f:
        data = f.read()

Mistake 2: Building paths with string concatenation instead of os.path.join or pathlib

# Wrong — breaks on Windows, fragile with trailing slashes
path = base_dir + "/" + filename

# Correct with os.path
import os
path = os.path.join(base_dir, filename)

# Correct with pathlib
from pathlib import Path
path = Path(base_dir) / filename

String concatenation produces paths that break on Windows (where the separator is \) and fails silently when base_dir already ends with a slash — or doesn't.

Mistake 3: Checking existence then opening without handling the race

# Race-prone — file could be deleted between check and open
if os.path.isfile("data.csv"):
    with open("data.csv") as f:  # could still raise FileNotFoundError
        process(f)

# Race-safe
try:
    with open("data.csv") as f:
        process(f)
except FileNotFoundError:
    print("data.csv was not found")

Summary

  • os.path.exists(path) — quick check for files or directories; not race-safe.
  • os.path.isfile(path) — confirms the path is a regular file.
  • os.path.isdir(path) — confirms the path is a directory.
  • Path.exists() / Path.is_file() / Path.is_dir() — modern pathlib equivalents, preferred for Python 3.4+.
  • try/except FileNotFoundError — the Pythonic, race-safe way to check existence right before using a file.

For most real-world code, combine pathlib for path construction with try/except for file access — that gives you clean, readable, and race-safe file handling.


Related Tutorials

Leonardo Lazzaro

Software engineer and technical writer. 10+ years experience in DevOps, Python, and Linux systems.

More articles by Leonardo Lazzaro