How to check if file exists in C++ in a portable way?

c, c++, file, portability, posix

Solution

Because C++ is also tagged, I would use `boost::filesystem`:

#include <boost/filesystem.hpp>

bool FileExist( const std::string& Name )
{
     return boost::filesystem::exists(Name);
}

Behind the scenes

Apparently, boost is using `stat` on POSIX and `DWORD attr(::GetFileAttributesW(FileName));` on Windows (Note: I've extracted the relevant parts of code here, it could be that I did something wrong, but this should be it).

Basically, besides return value, boost is checking errno value in order to check if file really does not exist, or your stat failed for a different reason.

#ifdef BOOST_POSIX_API

struct stat path_stat;
if (::stat(p.c_str(), &path_stat)!= 0)
{
  if (ec != 0)                            // always report errno, even though some
    ec->assign(errno, system_category());   // errno values are not status_errors

  if (not_found_error(errno))
  {
    return fs::file_status(fs::file_not_found, fs::no_perms);
  }
  if (ec == 0)
    BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status",
      p, error_code(errno, system_category())));
  return fs::file_status(fs::status_error);
}

#else
     DWORD attr(::GetFileAttributesW(p.c_str()));
     if (attr == 0xFFFFFFFF)
     {
         int errval(::GetLastError());
         if (not_found_error(errval))
         {
             return fs::file_status(fs::file_not_found, fs::no_perms);
         }
     }   
#endif

`not_found_error` is defined separately for Windows and for POSIX:

Windows:

bool not_found_error(int errval)
  {
    return errval == ERROR_FILE_NOT_FOUND
      || errval == ERROR_PATH_NOT_FOUND
      || errval == ERROR_INVALID_NAME  // "tools/jam/src/:sys:stat.h", "//foo"
      || errval == ERROR_INVALID_DRIVE  // USB card reader with no card inserted
      || errval == ERROR_NOT_READY  // CD/DVD drive with no disc inserted
      || errval == ERROR_INVALID_PARAMETER  // ":sys:stat.h"
      || errval == ERROR_BAD_PATHNAME  // "//nosuch" on Win64
      || errval == ERROR_BAD_NETPATH;  // "//nosuch" on Win32
  }

POSIX:

bool not_found_error(int errval)
  {
    return errno == ENOENT || errno == ENOTDIR;
  }

Problem

Currently I use this code to check if file exists on `Windows` and `POSIX`-compatible OSes (Linux, Android, MacOS, iOS, BlackBerry 10): ``` bool FileExist( const std::string& Name ) { #ifdef OS_WINDOWS struct _stat buf; int Result = _stat( Name.c_str(), &buf ); #else struct stat buf; int Result = stat( Name.c_str(), &buf ); #endif return Result == 0; } ``` Questions: Does this code have any pitfalls? (maybe an OS where it cannot be compiled) Is it possible to do it in a truly portable way using only C/C++ standard library? How to improve it? Looking for canonical example.

Original source

Related problems