13

目前,我使用此代码检查文件是否存在于WindowsPOSIX兼容的操作系统(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;
}

问题:

  1. 这段代码有什么陷阱吗?(可能是无法编译的操作系统)

  2. 是否可以仅使用 C/C++ 标准库以真正可移植的方式来完成它?

  3. 如何改进它?寻找典型的例子。

4

3 回答 3

20

因为 C++ 也被标记,所以我会使用boost::filesystem

#include <boost/filesystem.hpp>

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

在幕后

显然,boost 正在statPOSIX 和DWORD attr(::GetFileAttributesW(FileName));Windows 上使用(注意:我在这里提取了代码的相关部分,可能是我做错了什么,但应该是这样)。

基本上,除了返回值之外,boost 还会检查 errno 值以检查文件是否真的不存在,或者您的统计信息是否因其他原因而失败。

#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分别为 Windows 和 POSIX 定义:

视窗:

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;
  }
于 2013-08-19T18:29:11.257 回答
3

我个人喜欢尝试打开文件:

bool FileExist( const std::string& Name )
{
     std::ifstream f(name.c_str());  // New enough C++ library will accept just name
     return f.is_open();
}

应该适用于任何有文件的东西[C++ 标准不要求],因为它使用的是 C++ std::string,我不明白为什么std::ifstream会有问题。

于 2013-08-19T18:31:55.730 回答
1
  1. 这段代码有什么陷阱吗?(可能是无法编译的操作系统)

Result == 0"skips" ENAMETOOLONG, ELOOP, 错误等按照这个

我可以想到这一点:ENAMETOOLONG路径太长了:-

在许多情况下,在递归扫描期间,子文件夹/目录不断增加,如果路径“太”长,可能会导致此错误,但文件仍然存在!

其他错误也可能发生类似情况。

还,

按照这个,我更喜欢使用重载boost::filesystem::exists方法

bool exists(const path& p, system::error_code& ec) noexcept;

于 2013-08-19T19:02:20.557 回答