linux c语言 mkdir

99ANYc3cd6
预计阅读时长 23 分钟
位置: 首页 C语言 正文

mkdir()

mkdir 是一个标准的 POSIX 系统调用,用于创建一个新的空目录。

linux c语言 mkdir
(图片来源网络,侵删)

函数原型

#include <sys/stat.h>
#include <sys/types.h>
int mkdir(const char *pathname, mode_t mode);

参数说明

  • pathname (const char *):

    • 这是一个指向以 null 结尾的字符串的指针,表示你想要创建的目录的路径。
    • 路径可以是相对路径(相对于当前工作目录)或绝对路径(从根目录 开始)。
    • 如果路径中的任何父目录不存在,mkdir 会直接失败,并返回 ENOENT (错误号 2,No such file or directory)。
  • mode (mode_t):

    • 这个参数用于设置新创建目录的权限
    • 它是一个位掩码,通常用八进制数表示,0755
    • 权限由三部分组成:所有者所属组其他人
      • 7 (rwx): 所有者拥有读、写、执行权限。
      • 5 (r-x): 所属组拥有读、执行权限。
      • 5 (r-x): 其他人拥有读、执行权限。
    • 重要提示: 最终的权限不仅由 mode 参数决定,还会受到进程的 umask 值的影响,实际权限的计算公式为:实际权限 = mode & ~umask
    • 在 Linux 中,目录的执行权限 (x) 非常重要,它代表“进入”该目录的权限,没有执行权限,你无法 cd 到该目录中,即使你有读权限。

返回值

  • 成功: 返回 0
  • 失败: 返回 -1,并且会设置 errno 全局变量来指示具体的错误原因,你可以使用 perror() 函数或 strerror(errno) 来打印出可读的错误信息。

常见错误码 (errno)

  • EACCES (错误号 13, Permission denied):
    • 父目录的写权限被禁止。
    • 在文件系统中,mkdir 需要在父目录中拥有写权限,以便创建新的目录项。
  • EEXIST (错误号 17, File exists):
    • pathname 指定的目录已经存在。
  • ENOENT (错误号 2, No such file or directory):

    路径中的某个父目录不存在。

  • EROFS (错误号 30, Read-only file system):

    尝试在一个只读的文件系统上创建目录。

    linux c语言 mkdir
    (图片来源网络,侵删)
  • ENOSPC (错误号 28, No space left on device):

    设备上没有剩余空间了。


示例代码

下面是一些不同场景下的示例代码。

示例 1:创建一个简单的目录

这个例子创建一个名为 my_test_dir 的目录,并设置权限为 0755

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h> // 用于使用 errno
int main() {
    const char *dir_path = "my_test_dir";
    mode_t mode = 0755; // 八进制数,注意前缀 0
    // 尝试创建目录
    if (mkdir(dir_path, mode) == -1) {
        // 如果创建失败,打印错误信息
        perror("mkdir() failed"); // perror 会自动打印 "mkdir() failed: " 和具体的错误信息
        return 1; // 返回非零表示错误
    }
    printf("Directory '%s' created successfully.\n", dir_path);
    return 0;
}

如何编译和运行:

linux c语言 mkdir
(图片来源网络,侵删)
# 编译
gcc -o mkdir_example mkdir_example.c
# 运行
./mkdir_example
# 检查目录是否创建成功以及权限
ls -ld my_test_dir

输出:

Directory 'my_test_dir' created successfully.
drwxr-xr-x 2 user user 4096 Oct 27 10:30 my_test_dir

示例 2:处理错误(例如目录已存在)

这个例子展示了如何处理 EEXIST 错误。

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
int main() {
    const char *dir_path = "existing_dir";
    mode_t mode = 0700; // 仅所有者有读写执行权限
    // 先创建一次
    mkdir(dir_path, mode);
    // 尝试再次创建
    if (mkdir(dir_path, mode) == -1) {
        if (errno == EEXIST) {
            fprintf(stderr, "Error: Directory '%s' already exists.\n", dir_path);
        } else {
            perror("mkdir() failed for another reason");
            return 1;
        }
    } else {
        printf("Directory '%s' created successfully.\n", dir_path);
    }
    return 0;
}

示例 3:创建多级目录(mkdir -p 的功能)

标准的 mkdir 函数一次只能创建一级目录,如果父目录不存在,它会失败,要实现类似 mkdir -p 的功能(即如果父目录不存在,则一并创建),你需要自己编写逻辑,或者使用更现代的 mkdirat 配合 openO_DIRECTORYO_EXCL 标志来模拟。

一个简单的方法是递归地检查并创建父目录。

#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
// 递归创建多级目录
int create_directory_recursive(const char *path, mode_t mode) {
    // 检查路径是否已存在
    struct stat st;
    if (stat(path, &st) == 0) {
        if (S_ISDIR(st.st_mode)) {
            return 0; // 目录已存在,无需创建
        }
        return -1; // 路径存在但不是目录
    }
    // 如果父目录不存在,则递归创建父目录
    char *parent_path = strdup(path); // 复制路径,因为 dirname() 会修改字符串
    if (!parent_path) return -1;
    char *dir = dirname(parent_path); // 获取父目录路径
    if (strcmp(dir, ".") != 0 && strcmp(dir, "/") != 0) {
        if (create_directory_recursive(dir, mode) == -1) {
            free(parent_path);
            return -1;
        }
    }
    free(parent_path);
    // 创建当前目录
    if (mkdir(path, mode) == -1) {
        // 如果错误不是“已存在”,则报告错误
        if (errno != EEXIST) {
            perror("mkdir() failed");
            return -1;
        }
    }
    return 0;
}
int main() {
    const char *path = "a/b/c/d";
    mode_t mode = 0755;
    if (create_directory_recursive(path, mode) == 0) {
        printf("Recursive directory creation for '%s' successful.\n", path);
    } else {
        fprintf(stderr, "Failed to create directory '%s'.\n", path);
        return 1;
    }
    return 0;
}

如何编译和运行:

gcc -o mkdir_recursive mkdir_recursive.c
./mkdir_recursive
ls -ld a/b/c/d

现代 C 标准中的替代方案:std::filesystem (C++17)

如果你使用的是 C++17 或更高版本,标准库中提供了一个更安全、更易用的 std::filesystem 库,它不依赖于特定的操作系统 API,是跨平台的,并且功能更强大。

#include <iostream>
#include <filesystem> // C++17 filesystem 库
namespace fs = std::filesystem;
int main() {
    fs::path dir_path = "my_cpp_dir";
    // 创建单级目录
    try {
        if (fs::create_directory(dir_path)) {
            std::cout << "Directory " << dir_path << " created successfully.\n";
        } else {
            std::cout << "Directory " << dir_path << " already exists.\n";
        }
    } catch (const fs::filesystem_error& e) {
        std::cerr << "Filesystem error: " << e.what() << '\n';
        return 1;
    }
    // 创建多级目录 (相当于 mkdir -p)
    fs::path multi_path = "cpp/a/b/c";
    try {
        if (fs::create_directories(multi_path)) {
            std::cout << "Recursive directory creation for " << multi_path << " successful.\n";
        }
    } catch (const fs::filesystem_error& e) {
        std::cerr << "Filesystem error: " << e.what() << '\n';
        return 1;
    }
    return 0;
}

编译时需要链接 C++ 标准库并支持 C++17:

g++ -std=c++17 -o mkdir_cpp mkdir_cpp.cpp
./mkdir_cpp
特性 mkdir() (POS C) std::filesystem (C++17)
语言 C C++
标准 POSIX ISO C++17
平台 主要是 Unix-like (Linux, macOS) 跨平台
创建单级目录 mkdir(path, mode) fs::create_directory(path)
创建多级目录 需要自己实现逻辑 fs::create_directories(path) (内置支持)
错误处理 设置 errno,需手动检查 抛出 std::filesystem_error 异常
权限设置 通过 mode 参数 通过 fs::perms 枚举,与权限掩码结合

对于纯 C 语言开发,mkdir() 是标准且高效的选择,如果你有 C++ 的开发环境,强烈推荐使用 std::filesystem,它提供了更现代、更健壮的接口。

-- 展开阅读全文 --
头像
织梦dede_archives表如何高效管理文章数据?
« 上一篇 01-04
dedeclist如何输出完整地址?
下一篇 » 01-05

相关文章

取消
微信二维码
支付宝二维码

目录[+]