13

現在、このコードを使用してWindowsPOSIX互換性のある OS (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. このコードには落とし穴がありますか? (コンパイルできないOSかもしれません)

  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_errorWindows 用と 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. このコードには落とし穴がありますか? (コンパイルできないOSかもしれません)

Result == 0これによると、 「スキップ」、、ENAMETOOLONGエラーELOOPなど

私はこれを考えることができます:ENAMETOOLONGパスが長すぎます:-

多くの場合、再帰スキャン中にサブフォルダー/ディレクトリが増加し続けます。パスが「長すぎる」場合、このエラーが発生する可能性がありますが、ファイルは存在します!

他のエラーでも同様のケースが発生する可能性があります。

また、

thisに従って、オーバーロードされたboost::filesystem::existsメソッドを使用することを好みます

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

于 2013-08-19T19:02:20.557 に答える