Linux C语言mkdir函数如何正确使用?

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

mkdir 是一个用于创建目录的标准 C 库函数,它定义在 <sys/stat.h><unistd.h> 头文件中。

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

函数原型

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

参数说明

  1. pathname:

    • 类型:const char *
    • 说明:一个指向以 null 结尾的字符串的指针,该字符串指定了要创建的目录的路径。
    • 路径可以是绝对路径(以 开头)或相对路径(相对于当前工作目录)。
    • 如果路径中的任何父目录不存在,mkdir 函数会失败(返回 -1),并设置 errnoENOENT
  2. mode:

    • 类型:mode_t
    • 说明:指定新目录的权限(权限掩码)
    • 这个值是按位或()组合起来的,S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH
    • 重要提示mode 参数指定的权限不一定就是最终目录的权限,最终权限是 mode进程文件模式创建掩码(umask 进行按位与操作的结果。
    • 你设置 mode0777 (rwxrwxrwx),但你的 umask0002,那么最终创建的目录权限将是 0775 (rwxrwxr-x)。

返回值

  • 成功:返回 0
  • 失败:返回 -1,并且会设置 errno 全局变量来指明具体的错误原因。

常用 mode 宏定义

为了方便设置权限,C 标准库提供了一系列宏定义:

宏定义 八进制值 描述
S_IRUSR (S_IREAD) 00400 用户(所有者)读权限
S_IWUSR (S_IWRITE) 00200 用户(所有者)写权限
S_IXUSR (S_IEXEC) 00100 用户(所有者)执行权限
S_IRGRP 00040 组读权限
S_IWGRP 00020 组写权限
S_IXGRP 00010 组执行权限
S_IROTH 00004 其他用户读权限
S_IWOTH 00002 其他用户写权限
S_IXOTH 00001 其他用户执行权限
S_IRWXU 00700 用户(所有者)读、写、执行权限的组合
S_IRWXG 00070 组读、写、执行权限的组合
S_IRWXO 00007 其他用户读、写、执行权限的组合

权限的表示:在 C 代码中,权限通常用八进制数表示。

linux c语言mkdir
(图片来源网络,侵删)
  • 0755S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH,所有者有读写执行权限,组和其他用户有读和执行权限。
  • 0700S_IRWXU,只有所有者有读写执行权限。
  • 0777S_IRWXU | S_IRWXG | S_IRWXO,所有用户都有读写执行权限。

错误码 (errno)

mkdir 失败时,errno 会被设置为以下常见值之一:

  • EEXIST: 路径名已存在,并且不是一个符号链接。
  • EACCES: 文件所在目录的写权限被拒绝,或者进程的 umask 设置阻止了权限的创建。
  • ENOENT: 路径的前缀部分不存在(你想创建 /tmp/mydir/newdir,但 /tmp/mydir 不存在)。
  • EROFS: 文件系统所在的设备是只读的。
  • ENOSPC: 设备上没有剩余空间。
  • ENAMETOOLONG: pathname 过长。

完整示例代码

下面是一个完整的示例,展示了如何创建一个目录,并处理可能出现的错误。

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h> // 必须包含以使用 perror 和 errno
int main() {
    const char *dir_path = "./my_test_dir";
    // 定义目录权限:所有者 rwx, 组 r-x, 其他 r-x
    mode_t mode = 0755;
    // 调用 mkdir 函数
    int result = mkdir(dir_path, mode);
    if (result == 0) {
        printf("目录 '%s' 创建成功!\n", dir_path);
    } else {
        // 如果创建失败,perror 会打印 "mkdir: " 后面跟具体的错误信息
        // "mkdir: File exists" 或 "mkdir: Permission denied"
        perror("mkdir 错误");
        // 可以根据 errno 的值进行更详细的判断
        if (errno == EEXIST) {
            fprintf(stderr, "错误:目录 '%s' 已存在,\n", dir_path);
        } else if (errno == EACCES) {
            fprintf(stderr, "错误:没有权限创建目录 '%s',\n", dir_path);
        }
        // ... 可以添加更多错误类型的处理
    }
    return 0;
}

如何编译和运行:

  1. 将代码保存为 create_dir.c
  2. 打开终端,使用 gcc 进行编译:
    gcc create_dir.c -o create_dir
  3. 运行生成的可执行文件:
    ./create_dir

    第一次运行

    目录 './my_test_dir' 创建成功!

    再次运行(因为目录已存在):

    linux c语言mkdir
    (图片来源网络,侵删)
    mkdir 错误: File exists
    错误:目录 './my_test_dir' 已存在。

进阶:创建多级目录

标准的 mkdir 函数一次只能创建一级目录,如果你想创建类似 a/b/c/d 这样的多级目录,而 ab 等父目录可能不存在,mkdir 会直接失败。

这时,你需要使用 Linux 特有的系统调用 mkdirat 结合一个循环,或者更简单的方法是使用 system() 函数调用 shell 的 mkdir -p 命令。

使用 system() 函数(简单但不推荐用于生产环境)

#include <stdio.h>
#include <stdlib.h> // for system()
int main() {
    const char *path = "deep/nested/dir/structure";
    // system() 会调用 shell 执行命令
    // "mkdir -p" 会自动创建所有不存在的父目录
    // 如果目录已存在,"-p" 选项会静默忽略,不会报错
    int status = system("mkdir -p deep/nested/dir/structure");
    if (status == -1) {
        perror("system 调用失败");
    } else if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
        printf("多级目录 '%s' 创建成功!\n", path);
    } else {
        printf("mkdir 命令执行失败,退出码: %d\n", WEXITSTATUS(status));
    }
    return 0;
}

缺点

  • 依赖于 shell,移植性差。
  • 有额外的 shell 进程开销。
  • path 字符串中包含 shell 特殊字符(如 , &),可能会有安全风险(命令注入)。

手动实现(推荐)

更健壮的方法是手动实现一个创建多级目录的函数,这通常需要用到 stat()lstat() 来检查路径是否存在,以及 strtok() 来分割路径。

#include <stdio.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
// 创建多级目录的函数
int create_multi_dir(const char *path) {
    char tmp[256];
    char *p = NULL;
    size_t len;
    // 复制路径,避免修改原始字符串
    snprintf(tmp, sizeof(tmp), "%s", path);
    len = strlen(tmp);
    // 如果路径以 '/' 去掉它
    if(tmp[len - 1] == '/') {
        tmp[len - 1] = 0;
    }
    // 遍历路径,逐级创建
    for(p = tmp + 1; *p; p++) {
        if(*p == '/') {
            *p = 0; // 临时截断路径,检查父目录
            // 检查目录是否存在
            if (mkdir(tmp, 0755) != 0) {
                // 如果目录已存在,errno 会被设置为 EEXIST
                if (errno != EEXIST) {
                    perror("mkdir 错误");
                    return -1;
                }
            }
            *p = '/'; // 恢复路径
        }
    }
    // 创建最后一级目录
    if (mkdir(tmp, 0755) != 0 && errno != EEXIST) {
        perror("mkdir 错误");
        return -1;
    }
    return 0;
}
int main() {
    const char *path = "a/b/c/d";
    if (create_multi_dir(path) == 0) {
        printf("多级目录 '%s' 创建成功!\n", path);
    } else {
        printf("创建多级目录失败,\n");
    }
    return 0;
}

这个手动实现的函数更加高效和安全,不依赖于外部命令。


特性 mkdir mkdir -p (via system) 手动实现多级 mkdir
功能 创建单级目录 创建多级目录 创建多级目录
标准性 POSIX 标准,跨平台 Linux/Unix 特有,非标准 POSIX 标准,跨平台
依赖 依赖 /bin/sh
性能 较低(有 fork/exec 开销)
安全性 较低(有命令注入风险)
推荐场景 创建单级目录或已确认父目录存在的场景 快速脚本、原型开发 生产环境、库函数、需要高性能的场景

对于简单的单级目录创建,直接使用 mkdir 即可,对于复杂的多级目录创建,推荐手动实现的方法。

-- 展开阅读全文 --
头像
dede如何调用顶级栏目名称?
« 上一篇 前天
dede plus文件名如何修改?
下一篇 » 前天

相关文章

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

目录[+]