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

(图片来源网络,侵删)
函数原型
#include <sys/stat.h> #include <sys/types.h> int mkdir(const char *pathname, mode_t mode);
参数说明
-
pathname:- 类型:
const char * - 说明:一个指向以 null 结尾的字符串的指针,该字符串指定了要创建的目录的路径。
- 路径可以是绝对路径(以 开头)或相对路径(相对于当前工作目录)。
- 如果路径中的任何父目录不存在,
mkdir函数会失败(返回 -1),并设置errno为ENOENT。
- 类型:
-
mode:- 类型:
mode_t - 说明:指定新目录的权限(权限掩码)。
- 这个值是按位或()组合起来的,
S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH。 - 重要提示:
mode参数指定的权限不一定就是最终目录的权限,最终权限是mode和进程文件模式创建掩码(umask) 进行按位与操作的结果。 - 你设置
mode为0777(rwxrwxrwx),但你的umask是0002,那么最终创建的目录权限将是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 代码中,权限通常用八进制数表示。

(图片来源网络,侵删)
0755:S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH,所有者有读写执行权限,组和其他用户有读和执行权限。0700:S_IRWXU,只有所有者有读写执行权限。0777:S_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;
}
如何编译和运行:
- 将代码保存为
create_dir.c。 - 打开终端,使用
gcc进行编译:gcc create_dir.c -o create_dir
- 运行生成的可执行文件:
./create_dir
第一次运行:
目录 './my_test_dir' 创建成功!再次运行(因为目录已存在):
(图片来源网络,侵删)mkdir 错误: File exists 错误:目录 './my_test_dir' 已存在。
进阶:创建多级目录
标准的 mkdir 函数一次只能创建一级目录,如果你想创建类似 a/b/c/d 这样的多级目录,而 a 或 b 等父目录可能不存在,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 即可,对于复杂的多级目录创建,推荐手动实现的方法。
