Question

How to Check If a File Exists in Standard C++ (C++11, C++14, C++17)

cppcfilestream

Question

I need an efficient way to check whether a file exists using standard C++11, C++14, C++17, or C. I may need to process thousands of files, so before operating on them I want to verify that each file is present.

What can I write instead of /* SOMETHING */ in this function?

inline bool exist(const std::string& name)
{
    /* SOMETHING */
}

Short Answer

By the end of this page, you will understand the standard ways to check whether a file exists in C++, when to use std::ifstream versus std::filesystem::exists, why “exists” checks can be misleading in some workflows, and how this is typically handled in real codebases.

Concept

In C++, checking whether a file exists depends on which standard version you are using.

  • C++17 introduced std::filesystem, which provides a clear, standard way to work with paths and file status.
  • C++11/C++14 do not have standard filesystem support, so a common standard-only approach is to try opening the file with std::ifstream.
  • In C, the usual standard-library approach is trying to open the file with fopen.

A key idea: "checking if a file exists" is often really "checking whether I can access it right now."

That matters because:

  • A path may exist but refer to a directory, not a regular file.
  • A file may exist but you may not have permission to open it.
  • A file may be deleted or changed between the check and the actual use.

This is why many real programs prefer to perform the operation directly and handle failure, instead of doing a separate existence check first.

Still, existence checks are useful when:

  • validating input paths,
  • scanning a large batch of expected files,
  • reporting missing resources before processing starts,
  • filtering paths before attempting expensive work.

Standard approaches

C++17

Use std::filesystem::exists(path).

C++11 / C++14

Use std::ifstream and test whether the file stream opened successfully.

C

Use fopen and check whether it returns NULL.

Fastest way?

There is no universally fastest answer at the language level. Performance depends on:

  • operating system,
  • filesystem type,
  • disk cache,
  • permissions,
  • whether paths are local or network-based.

In practice:

  • std::filesystem::exists is the best standard semantic choice in C++17.
  • std::ifstream(name).good() or simply checking the stream state is the typical portable pre-C++17 choice.
  • If you are going to open the file anyway, opening it once and handling errors is often better than checking first and then opening again.

Mental Model

Think of a file path like a house address.

  • exists(path) asks: “Is there something at this address?”
  • Opening the file asks: “Can I actually enter and use this place?”

Those are not always the same.

A house may exist, but:

  • it might be locked,
  • it might be the wrong building,
  • it might disappear before you arrive.

So if your real goal is to read the file, the safest mindset is:

  1. Try to open it.
  2. If it opens, use it.
  3. If it fails, handle the error.

Use existence checks mainly when you truly need a separate validation step.

Take Quiz

Syntax and Examples

C++17: std::filesystem::exists

#include <filesystem>
#include <string>

inline bool exist(const std::string& name)
{
    return std::filesystem::exists(name);
}

This is the most direct standard solution in C++17.

If you specifically want to check for a regular file and not just any filesystem entry:

#include <filesystem>
#include <string>

inline bool exist(const std::string& name)
{
    return std::filesystem::is_regular_file(name);
}

This avoids returning true for directories.

C++11 / C++14: std::ifstream

#include <fstream>
#include <string>

inline bool exist(const std::string& name)
{
    std::ifstream file(name);
    return file.good();
}

This works because opening the stream will succeed only if the file can be opened for reading.

A shorter equivalent form is:

#include <fstream>
#include <string>

inline bool exist(const std::string& name)
{
    std::ifstream file(name);
    return static_cast<bool>(file);
}

C version

#include <stdio.h>
#include <stdbool.h>

bool exist(const char* name)
{
    FILE* file = fopen(name, "r");
    if (file != NULL) {
        fclose(file);
        return true;
    }
    return false;
}

Beginner example

#include <iostream>
#include <filesystem>

int main()
{
    std::string path = "data.txt";

    if (std::filesystem::exists(path)) {
        std::cout << "File exists\n";
    } else {
        std::cout << "File does not exist\n";
    }
}

This checks whether something exists at data.txt and prints the result.

Step by Step Execution

Consider this C++17 example:

#include <iostream>
#include <filesystem>

int main()
{
    std::string path = "report.txt";

    if (std::filesystem::exists(path)) {
        std::cout << "Found\n";
    } else {
        std::cout << "Missing\n";
    }
}

Step by step

  1. path is set to "report.txt".
  2. std::filesystem::exists(path) asks the operating system about that path.
  3. If the path exists:
    • the condition is true
    • Found is printed
  4. If the path does not exist:
    • the condition is false
    • Missing is printed

Trace example

Suppose the current directory contains:

  • report.txt
  • image.png

Then:

std::filesystem::exists("report.txt")  // true
std::filesystem::exists("missing.txt") // false

Important detail

If report.txt exists when checked, that does not guarantee it will still exist a moment later when you open it. This is why code like the following can still fail:

if (std::filesystem::exists("report.txt")) {
    std::ifstream file("report.txt");
    // opening may still fail
}

The file could be removed, locked, or become inaccessible between the check and the open.

Real World Use Cases

Batch file processing

A program may receive a list of expected input files and report which ones are missing before starting work.

for (const auto& path : paths) {
    if (!std::filesystem::exists(path)) {
        std::cout << path << " is missing\n";
    }
}

Loading configuration files

Applications often look for optional configuration files.

  • If the file exists, load it.
  • If not, fall back to defaults.

Verifying assets

Games, media tools, and web build systems may check whether required assets exist:

  • images,
  • shaders,
  • templates,
  • translation files.

Import pipelines

Data-processing scripts may skip rows that reference missing files.

CLI tools

A command-line program may validate a user-supplied path before performing an action and print a clearer error message.

Take Quiz

Real Codebase Usage

In real projects, developers rarely write a file-existence function in isolation without thinking about the next step.

Common pattern: try the real operation

If you are going to read the file anyway, do this:

#include <fstream>
#include <string>

bool loadFile(const std::string& name)
{
    std::ifstream file(name);
    if (!file) {
        return false;
    }

    // read file here
    return true;
}

This avoids checking once and then opening again.

Guard clause pattern

if (!std::filesystem::exists(path)) {
    return false;
}

This is useful when missing files should stop processing early.

Validation pattern

When accepting user input:

if (!std::filesystem::is_regular_file(path)) {
    throw std::runtime_error("Input path must be a file");
}

This is better than checking only exists, because directories also exist.

Error-handling pattern

C++17 filesystem functions may throw exceptions in some overloads. In larger codebases, developers may prefer overloads that use std::error_code.

#include <filesystem>
#include <system_error>

std::error_code ec;
bool ok = std::filesystem::exists("data.txt", ec);
if (ec) {
    // handle filesystem query error
}

This is useful in tools, servers, and libraries where exception-free error handling is preferred.

Filtering pattern

When scanning many paths:

std::vector<std::string> existing;
for (const auto& path : paths) {
    if (std::filesystem::exists(path)) {
        existing.push_back(path);
    }
}

This is common before running expensive processing steps.

Common Mistakes

1. Assuming exists() means “readable file”

Broken assumption:

if (std::filesystem::exists(path)) {
    std::ifstream file(path);
    // may still fail
}

Why it happens:

  • the path may be a directory,
  • permissions may block access,
  • the file may change after the check.

How to avoid it:

  • use is_regular_file(path) if you need a real file,
  • or simply try to open it and handle failure.

2. Checking first, then opening unnecessarily

if (std::filesystem::exists(path)) {
    std::ifstream file(path);
}

This may do extra work and still is not fully safe.

Better:

std::ifstream file(path);
if (!file) {
    // handle missing or inaccessible file
}

3. Forgetting to close FILE* in C

Broken code:

bool exist(const char* name)
{
    return fopen(name, "r") != NULL;
}

Problem: if fopen succeeds, the file handle is leaked.

Correct version:

bool exist(const char* name)
{
    FILE* file = fopen(name, "r");
    if (file) {
        fclose(file);
        return true;
    }
    return false;
}

4. Using exists() when you really need a file type check

exists("mydir") returns true for directories too.

Use this when appropriate:

std::filesystem::is_regular_file("mydir")

5. Ignoring C++ version differences

This will not work in standard C++11/C++14:

#include <filesystem>

Use std::ifstream if you need a standard-only solution before C++17.

Comparisons

ApproachStandard VersionWhat it checksGood forLimitation
std::filesystem::exists(path)C++17+Whether a filesystem entry existsClear path checksMay be true for directories too
std::filesystem::is_regular_file(path)C++17+Whether the path exists and is a normal fileInput file validationStill does not guarantee readable/openable
std::ifstream file(path); if (file)C++11+Whether the file could be opened for readingPortable pre-C++17 solutionTests openability, not pure existence
fopen(path, "r")CWhether the file could be opened for readingStandard CMust remember fclose
Open-and-handle-error directlyAllWhether your real operation succeedsBest for actual file processingNot a separate existence check

exists vs is_regular_file

FunctionReturns true for filesReturns true for directoriesBest use
exists(path)YesYesGeneral path presence check
is_regular_file(path)YesNoConfirming you have a normal file

Which one should you choose?

  • Using C++17 and just need to know whether the path exists? Use std::filesystem::exists.
  • Using C++17 and need to ensure it is a file? Use std::filesystem::is_regular_file.
  • Using C++11/C++14 only? Use std::ifstream.
  • Going to open the file anyway? Just open it and handle failure.
Take Quiz

Cheat Sheet

// C++17: path exists
#include <filesystem>
bool existsPath(const std::string& name) {
    return std::filesystem::exists(name);
}

// C++17: regular file exists
#include <filesystem>
bool existsFile(const std::string& name) {
    return std::filesystem::is_regular_file(name);
}

// C++11/C++14: try opening
#include <fstream>
bool existsFile(const std::string& name) {
    std::ifstream file(name);
    return file.good();
}
// C: try opening
#include <stdio.h>
#include <stdbool.h>

bool exist(const char* name) {
    FILE* file = fopen(name, "r");
    if (file) {
        fclose(file);
        return true;
    }
    return false;
}

Rules to remember

  • std::filesystem is standard in C++17 and later.
  • exists(path) checks whether something exists at the path.
  • is_regular_file(path) checks whether it is a normal file.
  • ifstream is the usual standard-only solution in C++11/C++14.
  • If you will read the file next, opening it directly is often better.
  • A successful existence check does not guarantee the next operation will succeed.

Edge cases

  • Directories also “exist”.
  • Permissions can block opening.
  • Network or removable drives may behave differently.
  • Files can change between checking and use.

FAQ

How do I check if a file exists in standard C++17?

Use std::filesystem::exists(path). If you specifically need a normal file, use std::filesystem::is_regular_file(path).

How do I check if a file exists in C++11 or C++14 without non-standard libraries?

Use std::ifstream and check whether the stream opened successfully.

Is std::filesystem::exists faster than std::ifstream?

Not always in a meaningful, portable way. Performance depends on the OS and filesystem. Choose the approach that best matches your intent.

Should I check if the file exists before opening it?

Usually not if you plan to open it immediately. Just open it and handle failure.

Does exists() return true for directories?

Yes. If you need a real file, prefer std::filesystem::is_regular_file().

Can exists() still be followed by a failed file open?

Yes. Permissions, file type, or timing changes can cause the later open to fail.

What is the standard C way to check file existence?

Use fopen(path, "r"), check for NULL, and call fclose if opening succeeded.

Take Quiz

Mini Project

Description

Build a small file validator that checks a list of input paths and reports whether each path is a regular file, missing, or not a regular file. This demonstrates practical use of C++17 filesystem checks in a way similar to real import tools and batch-processing scripts.

Goal

Create a program that validates several paths and prints a clear status for each one.

Requirements

  • Read a hardcoded list of file paths from a vector.
  • For each path, print whether it is missing, exists as a regular file, or exists but is not a regular file.
  • Use C++17 std::filesystem functions.
  • Keep the output easy to understand.
  • Avoid crashing if a path cannot be queried.
Take Quiz

Keep learning

Related questions

View more