关于C ++: 确定Linux中是否存在目录(不是文件)

C++ - Determining if directory (not a file) exists in Linux

本问题已经有最佳答案,请猛点这里访问。

如何确定在Linux中使用C++的目录(不是文件)存在吗?我尝试使用stat()函数,但当找到文件时,它返回正值。我只想找出输入的字符串是否是一个目录,而不是别的什么。


根据man(2)stat,您可以在st_模式字段上使用s_isdir宏:

1
bool isdir = S_ISDIR(st.st_mode);

另一方面,我建议使用boost和/或qt4,如果您的软件可以在其他OSS上运行,那么跨平台支持就更容易了。


我在这里找到的东西怎么样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <dirent.h>

bool DirectoryExists( const char* pzPath )
{
    if ( pzPath == NULL) return false;

    DIR *pDir;
    bool bExists = false;

    pDir = opendir (pzPath);

    if (pDir != NULL)
    {
        bExists = true;    
        (void) closedir (pDir);
    }

    return bExists;
}

或使用STAT

1
2
3
4
5
struct stat st;
if(stat("/tmp",&st) == 0)
    if(st.st_mode & S_IFDIR != 0)
        printf(" /tmp is present
"
);


如果可以查看boost文件系统库。这是一种以通用和可移植的方式处理此类问题的好方法。

在这种情况下,可以使用:

1
2
3
4
#include"boost/filesystem.hpp"  
using namespace boost::filesystem;
...
if ( !exists("test/mydir" ) ) {bla bla}


我理解你的问题的方式是:你有一条路径,比如说,/foo/bar/baz(baz是一个文件),你想知道/foo/bar是否存在。如果是这样,解决方案看起来像这样(未经测试):

1
2
3
4
5
char *myDir = dirname(myPath);
struct stat myStat;
if ((stat(myDir, &myStat) == 0) && (((myStat.st_mode) & S_IFMT) == S_IFDIR)) {
    // myDir exists and is a directory.
}


如果你想知道一个目录是否存在是因为你想对它做些什么(在里面创建一个文件/目录,扫描它的内容等),你应该继续做你想做的,然后检查它是否失败,如果失败,向用户报告strerror(errno)。这是在Unix下进行编程的一个一般原则:不要试图弄清楚您想要做的事情是否有效。尝试一下,然后看看是否失败。

如果您想在某个目录不存在(例如,如果您想创建一个文件和所有必要的包含目录)而导致失败时采取特殊的行为,那么在open失败后,您需要检查errno == ENOENT

我看到有人建议使用boost::filesystem。我想支持这个建议,但遗憾的是我不能,因为boost::filesystem不只是header,而且Boost的所有非header-only模块都有一个可怕的跟踪记录,如果您在不重新编译应用程序的情况下升级共享库,或者即使您没有用完全相同的方法编译应用程序,都会导致神秘的中断。用于编译共享库的标志。维护的痛苦是不值得的。


在C++ 17 **中,EDCOX1(7)提供了两个变量来确定路径的存在:

  • is_directory()确定路径是否是一个目录并且确实存在于实际的文件系统中。
  • exists()只是确定路径是否存在于实际的文件系统中(如果是目录,则不检查)。
  • 示例(无错误处理):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    #include <iostream>
    #include <filesystem> // C++17
    //#include <experimental/filesystem> // C++14
    namespace fs = std::filesystem;
    //namespace fs = std::experimental::filesystem; // C++14

    int main()
    {
        // Prepare.
        const auto processWorkingDir = fs::current_path();
        const auto existingDir = processWorkingDir /"existing/directory"; // Should exist in file system.
        const auto notExistingDir = processWorkingDir /"fake/path";
        const auto file = processWorkingDir /"file.ext"; // Should exist in file system.

        // Test.
        std::cout
            <<"existing dir:\t" << fs::is_directory(existingDir) <<"
    "

            <<"fake dir:\t" << fs::is_directory(notExistingDir) <<"
    "

            <<"existing file:\t" << fs::is_directory(file) <<"

    "
    ;

        std::cout
            <<"existing dir:\t" << fs::exists(existingDir) <<"
    "

            <<"fake dir:\t" << fs::exists(notExistingDir) <<"
    "

            <<"existing file:\t" << fs::exists(file);
    }

    可能的输出:

    1
    2
    3
    4
    5
    6
    7
    existing dir:   1
    fake dir:       0
    existing file:  0

    existing dir:   1
    fake dir:       0
    existing file:  1

    **在C++ 14中使用EDCOX1(10)

    两个函数都会在出现错误时抛出filesystem_error。如果要避免捕获异常,请使用带有std::error_code的重载变量作为第二个参数。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    #include <filesystem>
    #include <iostream>
    namespace fs = std::filesystem;

    bool isExistingDir(const fs::path& p) noexcept
    {
        try
        {
            return fs::is_directory(p);
        }
        catch (std::exception& e)
        {
            // Output the error message.
            const auto theError = std::string{ e.what() };
            std::cerr << theError;

            return false;
        }
    }

    bool isExistingDirEC(const fs::path& p) noexcept
    {
        std::error_code ec;
        const auto isDir = fs::is_directory(p, ec);
        if (ec)
        {
            // Output the error message.
            const auto theError = ec.message();
            std::cerr << theError;

            return false;
        }
        else
        {
            return isDir;
        }
    }

    int main()
    {
        const auto notExistingPath = fs::path{"\xa0\xa1" };
        isExistingDir(notExistingPath);
        isExistingDirEC(notExistingPath);
    }