【问题标题】:C++ - Determining if directory (not a file) exists in Linux [duplicate]C ++ - 确定Linux中是否存在目录(不是文件)[重复]
【发布时间】:2011-06-26 05:36:04
【问题描述】:

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

【问题讨论】:

  • stat() 应该可以工作。你是怎么用的?
  • 结构统计数据; cout
  • 恕我直言,重复标志不正确,因为另一个问题是关于搜索系统调用,而这个问题是关于 C++ 中的一般方法。

标签: c++ linux directory exists


【解决方案1】:

根据man(2) stat,您可以在 st_mode 字段上使用 S_ISDIR 宏:

bool isdir = S_ISDIR(st.st_mode);

旁注,如果您的软件可以在其他操作系统上运行,我建议使用 Boost 和/或 Qt4 来简化跨平台支持。

【讨论】:

  • 在#include 之后我得到编译器错误,g++ 报告“错误:'S_IDDIR' 没有在这个范围”。有人知道会发生什么吗?
  • 呸。错字。 S_IDDIR -> S_ISDIR。
【解决方案2】:

我找到的东西怎么样here

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

或使用统计数据

struct stat st;
if(stat("/tmp",&st) == 0)
    if(st.st_mode & S_IFDIR != 0)
        printf(" /tmp is present\n");

【讨论】:

  • 它可能没那么糟糕,但上面给出的例子并不是那么有效,底部的例子是我已经在使用的,除了我使用的是 != 而不是 ==
  • 你需要用 DarkDust 的额外 and 条件更新底部的。 (myStat.st_mode) &amp; S_IFMT) == S_IFDIR)。谢谢 DarkDust。
  • 上面给出的例子是唯一对我有用的例子,所以我现在接受它作为答案。
  • 不需要在目录上尝试opendir;使用 S_ISDIR 宏。
  • 你是说如果目录存在应该是 if(st.st_mode & S_IFDIR == 0) ???
【解决方案3】:

如果您可以查看boost filesystem library。这是以通用和可移植的方式处理此类问题的好方法。

在这种情况下,使用就足够了:

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

【讨论】:

  • 致命错误:boost/filesystem.hpp:没有此类文件或目录编译终止。
  • 嗯,你需要下载并安装 boost... 但我怀疑你会后悔 :)
  • 安装后仍然无法正常工作,“使用声明中不允许命名空间‘boost::filesystem’”:/
  • 抱歉,已更正答案...
  • 为什么是提升黑暗之路?
【解决方案4】:

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

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

【讨论】:

  • 不,我的意思是 "/foo/bar/baz" 和 "/foo/bar/baz" 使用相同将被视为相同的字符串,但一个 baz 是一个目录,另一个是一份文件。使用 stat() 它只告诉我字符串是否存在,而不是它是否是文件或目录。
  • 这怎么可能发生?您不能有两个具有相同名称的不同目录条目; /foo/bar/baz 不存在,或者它存在并且是一个目录,或者它存在并且不是一个目录;它不能作为一个目录而不是一个目录存在。
  • 啊,所以你想知道它是什么。在这种情况下,OneOfOne 的答案就是你想要的。
  • 这也是一个正确的答案,只是使用st_mode &amp; S_IFMT 而不是S_ISDIR 风格很差。
  • @MetaDark: stat doesst_mode 标志中告诉您路径是否为目录。使用我的代码检查目录标志或S_ISDIR 宏,如 OneOfOne 的答案所示。
【解决方案5】:

在 C++17** 中,std::filesystem 提供了两种变体来确定路径的存在:

  1. is_directory() 确定路径是否是目录并且是否存在于实际文件系统中
  2. exists() 只是确定路径是否存在于实际文件系统中(不检查,如果它是目录)

示例(无错误处理):

#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) << "\n"
        << "fake dir:\t" << fs::is_directory(notExistingDir) << "\n"
        << "existing file:\t" << fs::is_directory(file) << "\n\n";

    std::cout
        << "existing dir:\t" << fs::exists(existingDir) << "\n"
        << "fake dir:\t" << fs::exists(notExistingDir) << "\n"
        << "existing file:\t" << fs::exists(file);
}

可能的输出:

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

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

**在 C++14 中 std::experimental::filesystem 可用


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

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

【讨论】:

  • 为什么先使用is_directory(),然后再使用exists()?另外,真的需要exists() 吗?
  • 在 Windows 上,我做了:if (!is_directory("myDir")) { create_directory("myDir"); if (!is_directory("myDir")) { return false; } },它工作得很好(如果文件夹不存在则创建该文件夹,如果它作为文件夹存在则不创建,如果它存在则返回 false一个文件)。
  • @Andrew 感谢您的提示,exists() 确实是多余的!我已经更新了这个例子。由于问题不包括创建目录,我在答案中省略了。
【解决方案6】:

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

如果您想在由于目录不存在(例如,如果您要创建文件和所有必要的包含目录)而失败时采取特殊行为,则在 open 之后检查 errno == ENOENT失败。

我看到一位响应者建议使用boost::filesystem。我喜欢支持这个建议,但遗憾的是我不能,因为boost::filesystem 不是仅标题,而且 Boost 的所有非仅标题模块都有一个可怕的记录,如果您升级共享库而不重新编译应用程序,或者即使您没有设法使用与编译共享库相同的标志完全编译您的应用程序。维护的痛苦是不值得的。

【讨论】:

  • 如果它检测到它是它的文件,它仍然会继续并创建一个看似损坏的 tar 文件。哦,是的,如果我还没有说的话,我正在尝试 tar 目录。
  • 从目录创建存档的第一步是扫描目录,那么为什么不能直接调用opendir 看看它是否失败(应用于普通文件时应该这样做) ?
猜你喜欢
  • 2013-11-30
  • 1970-01-01
  • 2013-04-07
  • 1970-01-01
  • 2019-01-18
  • 1970-01-01
  • 2017-06-11
  • 2023-03-11
  • 2012-05-26
相关资源
最近更新 更多