【问题标题】:Checking if a directory exists in Unix (system call)检查 Unix 中是否存在目录(系统调用)
【发布时间】:2011-04-19 04:43:07
【问题描述】:

我无法在网上找到解决问题的方法。

我想在 Unix 中调用一个函数,传入一个目录的路径,并知道它是否存在。 opendir() 如果目录不存在则返回错误,但我的目标不是实际打开,检查错误,如果没有错误则关闭它,而只是检查文件是否为目录。

请问有什么方便的方法吗?

【问题讨论】:

  • 你为什么要在这个问题上写系统调用?你真的想要一个系统调用,它可能只适用于单一类型的操作系统(linux、BSD 等),还是来自 posix c 头文件的 POSIX 函数(应该适用于任何 UNIX 发行版)会做吗?
  • 如果您要寻找更多不依赖系统调用的答案,请参阅C++ - Determining if directory (not a file) exists in Linux

标签: c++ c unix directory exists


【解决方案1】:

在 POSIX 系统上有两个相关函数:stat() and lstat()。这些用于查明路径名是否引用了您有权访问的实际对象,如果是,则返回的数据会告诉您它是什么类型的对象。 stat()lstat() 之间的区别在于,如果您给出的名称是符号链接,stat() 会跟随符号链接(或链接,如果它们链接在一起)并报告位于链末尾的对象链接,而lstat() 报告符号链接本身。

#include <sys/stat.h>

struct stat sb;

if (stat(pathname, &sb) == 0 && S_ISDIR(sb.st_mode))
{
    ...it is a directory...
}

如果函数显示成功,则使用来自&lt;sys/stat.h&gt; 的 S_ISDIR() 宏来确定文件是否实际上是目录。

您还可以使用其他 S_IS* 宏检查其他文件类型:

  • S_ISDIR — 目录
  • S_ISREG — 常规文件
  • S_ISCHR — 字符设备
  • S_ISBLK — 块设备
  • S_ISFIFO — 先进先出
  • S_ISLNK — 符号链接
  • S_ISSOCK — 套接字

(一些系统也提供一些其他文件类型;例如,S_ISDOOR 在 Solaris 上可用。)

【讨论】:

  • stat 期望路径名参数是一个字符?
  • 不是char,而是char *——一个字符串。函数的 POSIX 规范的链接显示stat()lstat() 的第一个参数是const char * restrict pathname
  • 查看here 以查看有关S_IS* 宏的更多信息
  • @m4l490n:来自&lt;sys/stat.h&gt; 的 POSIX 规范,如答案中所链接。它的定义如下:S_ISBLK(m) — 测试块特殊文件。
【解决方案2】:

您可以通过将目录名称作为第一个参数传递给stat 系统调用来使用它。如果目录存在,则返回0,否则返回-1,errno 将设置为ENOENT

编辑:

如果返回值为0,则需要额外检查以确保参数实际上是一个目录,而不是文件/符号链接/char 特殊文件/blk 特殊文件/FIFO 文件。为此,您可以使用stat structurest_mode 字段。

【讨论】:

    【解决方案3】:

    如果你并不真正关心这个文件系统对象的类型,access(name, F_OK) 会检查这个名字的东西是否存在。 如果您需要确定这是目录,请使用 stat() 并使用 S_ISDIR() 宏检查类型。

    【讨论】:

    • 请注意,如果真实和有效的 UID 不同(您正在运行一个 setuid 程序),那么 access() 系统调用会回答与 stat() 不同的问题。具体来说,它检查真实 UID (RUID) 是否可以访问文件,而所有其他系统调用都使用有效 UID (EUID) — 包括 opendir()
    • 使用 F_OK 标志时,access() 实际上并不检查访问权限,它只是检查文件/目录/等是否存在。
    • 但是即使使用F_OK,如果传递给access() 的名称具有多个路径组件并且当前进程(EUID)没有权限搜索其中一个前导目录组件(因此它检查是否存在简单文件名 OK,但它可能会遇到非简单文件名的问题)。
    【解决方案4】:

    另一种简单的方法是:

    int check(unsigned const char type) {
        if(type == DT_REG)
            return 1;
        if(type == DT_DIR)
            return 0;
        return -1;
    }
    

    然后您可以将 struct dirent* 对象的 d_type 传递给 check 函数。

    如果检查返回 1,则该路径指向常规文件。

    如果检查返回 0,则该路径指向一个目录。

    否则,它既不是文件也不是目录(可以是块设备/符号链接等)

    【讨论】:

      猜你喜欢
      • 2013-01-08
      • 1970-01-01
      • 2017-08-28
      • 1970-01-01
      • 2011-01-18
      • 2010-12-26
      • 1970-01-01
      • 1970-01-01
      • 2018-05-13
      相关资源
      最近更新 更多