且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何检查是否文件用C ++存在一个可移植的方式?

更新时间:2023-11-25 16:38:46

由于C ++也被标记,我会使用的boost ::文件系统

 的#include<升压/ filesystem.hpp>布尔FileExist(常量标准::字符串&放大器;名称)
{
     返回的boost ::文件系统::存在(姓名);
}

幕后

显然,提升使用统计对POSIX和 DWORD ATTR(:: GetFileAttributesW(文件名)); 上视窗(注:我已经提取code的相关部分在这里,它可能是我做错了什么,但是这应该是吧)。

基本上,除了返回值,提振正在检查错误值,以检查文件确实不存在,或者您Stat失败出于不同的原因。

  #IFDEF BOOST_POSIX_API结构统计path_stat;
如果(::统计(p.c_str(),放大器;!path_stat)= 0)
{
  如果(EC!= 0)//总是报告错误号,即使有些
    EC-GT&;分配(错误,system_category()); // errno值不status_errors  如果(not_found_error(错误))
  {
    返回FS :: file_status(FS :: FILE_NOT_FOUND,FS :: no_perms);
  }
  如果(EC == 0)
    BOOST_FILESYSTEM_THROW(filesystem_error(提振::文件系统::地位,
      P,错误_ code(错误,system_category())));
  返回FS :: file_status(FS :: STATUS_ERROR);
}#其他
     DWORD ATTR(:: GetFileAttributesW(p.c_str()));
     如果(ATTR == 0xFFFFFFFF的)
     {
         INT errval(:: GetLastError函数());
         如果(not_found_error(errval))
         {
             返回FS :: file_status(FS :: FILE_NOT_FOUND,FS :: no_perms);
         }
     }
#万一

not_found_error 为Windows和POSIX分别定义:

Windows系统:

 布尔not_found_error(INT errval)
  {
    返回errval == ERROR_FILE_NOT_FOUND
      || errval == ERROR_PATH_NOT_FOUND
      || errval == ERROR_INVALID_NAME //工具/果酱/ src目录/:SYS:stat.h,//富
      ||配备无卡errval == ERROR_INVALID_DRIVE // USB读卡器插入
      || errval == ERROR_NOT_READY //无碟CD / DVD驱动器插入
      || errval == ERROR_INVALID_PARAMETER //:SYS:stat.h
      || errval == ERROR_BAD_PATHNAME //// nosuchWin64上
      || errval == ERROR_BAD_NETPATH​​; //// nosuch在Win32
  }

POSIX:

 布尔not_found_error(INT errval)
  {
    返回错误号== || ENOENT错误号== ENOTDIR;
  }

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:

  1. Does this code have any pitfalls? (maybe an OS where it cannot be compiled)

  2. Is it possible to do it in a truly portable way using only C/C++ standard library?

  3. How to improve it? Looking for canonical example.

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;
  }