SysTutorials

Checking if a Path is a Directory or File in C++

· updated April 11, 2026

Determining whether a path points to a directory or regular file is a common task in system programming. You need to stat the path and inspect the file mode.

Using lstat() and stat macros

The lstat() system call retrieves file metadata into a struct stat. For a given path, you can use the standard macros S_ISDIR(), S_ISREG(), and others to test the file type based on the st_mode field.

Key differences between stat() and lstat():

Use lstat() when you need to detect and handle symlinks separately. Use stat() when you want transparent link dereferencing.

Basic implementation

Here’s a working example:

#include <sys/stat.h>
#include <iostream>
#include <string>
#include <cstring>

std::string pathtype(const std::string& path) {
    struct stat s;

    if (lstat(path.c_str(), &s) != 0) {
        return "error";
    }

    if (S_ISDIR(s.st_mode)) {
        return "a dir";
    } else if (S_ISREG(s.st_mode)) {
        return "a file";
    } else if (S_ISLNK(s.st_mode)) {
        return "a symlink";
    } else {
        return "unknown";
    }
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        std::cerr << "Usage: " << argv[0] << " path\n";
        return 1;
    }

    std::cout << pathtype(argv[1]) << "\n";
    return 0;
}

Compile with:

g++ -o pathtype pathtype.cpp

Test it:

$ touch /tmp/file.txt
$ ./pathtype /tmp/file.txt
a file

$ mkdir /tmp/dir.txt
$ ./pathtype /tmp/dir.txt
a dir

$ ln -s /tmp/file.txt /tmp/link.txt
$ ./pathtype /tmp/link.txt
a symlink

Other file type checks

The <sys/stat.h> header provides additional macros for other file types:

Modern C++ approach using std::filesystem

For new C++ projects (C++17 and later), prefer std::filesystem for cleaner, more portable code:

#include <filesystem>
#include <iostream>

namespace fs = std::filesystem;

int main(int argc, char *argv[]) {
    if (argc < 2) {
        std::cerr << "Usage: " << argv[0] << " path\n";
        return 1;
    }

    try {
        fs::path p(argv[1]);

        if (fs::is_directory(p)) {
            std::cout << p << " is a dir\n";
        } else if (fs::is_regular_file(p)) {
            std::cout << p << " is a file\n";
        } else if (fs::is_symlink(p)) {
            std::cout << p << " is a symlink\n";
        } else {
            std::cout << p << " type is unknown\n";
        }
    } catch (const fs::filesystem_error& e) {
        std::cerr << "Error: " << e.what() << "\n";
        return 1;
    }

    return 0;
}

Compile with C++17 support:

g++ -std=c++17 -o pathtype pathtype.cpp

The std::filesystem approach is preferred because it:

Error handling

Always check the return value of lstat(). A return value of -1 indicates failure; check errno for the specific error:

#include <cerrno>

if (lstat(path.c_str(), &s) != 0) {
    std::cerr << "lstat failed: " << std::strerror(errno) << "\n";
    return 1;
}

Common errors:

← All posts