在 Linux C 开发中,文件与目录操作是高频场景,但相关结构体繁多,容易混淆。本文对 5 个核心结构体进行系统梳理,帮助开发者快速掌握其用途与区别,避免踩坑。
我在做 Linux 嵌入式开发时,经常和这几个结构体打交道,踩过不少坑。今天我把它们的核心知识点和避坑指南整理出来,希望能帮到大家。
1. struct dirent:目录项结构
-
定义:#include <dirent.h>
-
作用:存储目录中单个文件的元信息(文件名、inode 号等)。
-
典型流程:opendir() → readdir() → closedir()
-
核心成员:
-
d_name:文件名
-
d_ino:文件 inode 号
-
#include <dirent.h>
#include <stdio.h>
int main() {
DIR *dir = opendir(".");
struct dirent *ent;
while ((ent = readdir(dir)) != NULL) {
printf("%s\\n", ent->d_name);
}
closedir(dir);
return 0;
}
2. struct stat:文件属性结构
-
定义:#include <sys/stat.h>
-
作用:获取文件的详细属性(大小、类型、权限、时间戳等)。
-
典型函数:stat() / lstat() / fstat()
-
核心成员:
-
st_size:文件大小(字节)
-
st_mode:文件类型与权限(需配合掩码 S_IFMT、0777 使用,例如 S_ISREG(st_mode) 判断是否为普通文件)
-
st_mtime:最后修改时间
-
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
int main() {
struct stat st;
if (stat("test.txt", &st) == 0) {
printf("Size: %ld bytes\\n", st.st_size);
if (S_ISREG(st.st_mode)) {
printf("Regular file\\n");
}
printf("Permissions: %o\\n", st.st_mode & 0777);
} else {
perror("stat failed");
}
return 0;
}
3. DIR:目录句柄
-
定义:#include <dirent.h>
-
作用:代表一个已打开的目录,作为遍历目录的操作句柄。
-
典型流程:opendir() 打开目录 → readdir() 读取目录项 → closedir() 关闭。
-
注意:DIR 是不透明类型,内部结构由系统实现,不应直接访问。
#include <dirent.h>
#include <stdio.h>
#include <string.h>
int main() {
// 1. 打开当前目录,获取DIR句柄
DIR *dir_ptr = opendir(".");
if (dir_ptr == NULL) { // 必加错误检查,贴近实际开发
perror("opendir failed");
return 1;
}
struct dirent *ent_ptr;
// 2. 循环读取目录项,直到readdir返回NULL
while ((ent_ptr = readdir(dir_ptr)) != NULL) {
// 过滤.和..目录,避免无意义输出(实际开发常用技巧)
if (strcmp(ent_ptr->d_name, ".") == 0 || strcmp(ent_ptr->d_name, "..") == 0) {
continue;
}
printf("文件名:%s | inode号:%ld\\n", ent_ptr->d_name, ent_ptr->d_ino);
}
// 3. 关闭DIR句柄,避免资源泄漏
closedir(dir_ptr);
return 0;
}
4. FILE:文件流句柄
-
定义:#include <stdio.h>
-
作用:标准 C 库提供的文件操作句柄,支持缓冲 I/O。
-
典型流程:fopen() 打开文件 → fread()/fwrite() 读写 → fclose() 关闭。
-
与文件描述符的关系:可通过 fileno(FILE*) 获取底层文件描述符,用于更底层的操作。
#include <stdio.h>
#include <string.h>
int main() {
// 1. 打开文件(w+:读写模式,不存在则创建,存在则清空)
FILE *fp = fopen("test.txt", "w+");
if (fp == NULL) { // 必加错误检查
perror("fopen failed");
return 1;
}
// 2. 写入数据(带缓冲,实际开发常用fputs/fprintf)
const char *content = "Linux C FILE结构体示例\\n";
fputs(content, fp);
// 3. 移动文件指针到开头,准备读取
fseek(fp, 0, SEEK_SET);
// 4. 读取数据并打印
char buf[1024] = {0};
fgets(buf, sizeof(buf), fp);
printf("读取到的内容:%s", buf);
// 5. 可选:获取底层文件描述符(对接Linux系统调用)
int fd = fileno(fp);
printf("FILE对应的文件描述符:%d\\n", fd);
// 6. 关闭文件,释放缓冲+句柄
fclose(fp);
return 0;
}
5. glob_t:路径匹配结构
-
定义:#include <glob.h>
-
作用:用于批量匹配文件路径(如 *.c、/usr/bin/*)。
-
典型函数:glob() 执行匹配 → globfree() 释放资源。
-
核心成员:
-
gl_pathv:匹配到的路径数组
-
gl_pathc:匹配到的路径数量
-
#include <glob.h>
#include <stdio.h>
int main() {
glob_t g;
if (glob("./*.c", 0, NULL, &g) == 0) {
for (size_t i = 0; i < g.gl_pathc; i++) {
printf("%s\\n", g.gl_pathv[i]);
}
}
globfree(&g);
return 0;
}
核心区别速查表
| struct dirent | 存储目录项信息 | readdir() | 遍历目录、列出文件名 |
| struct stat | 获取文件属性 | stat() / lstat() | 查文件大小、类型、权限 |
| DIR | 目录操作句柄 | opendir() / closedir() | 打开、遍历目录 |
| FILE | 文件流操作 | fopen() / fclose() | 读写普通文件(带缓冲) |
| glob_t | 批量路径匹配 | glob() / globfree() | 批量查找 .c 文件等 |
风险提示(必看)
线程安全:在多线程环境中,使用 DIR 和 FILE 句柄时需要注意线程安全,避免并发读写导致数据混乱。
路径安全:使用 glob() 函数时,要注意路径匹配的安全性,避免因用户输入导致的路径遍历漏洞。
资源泄漏:所有打开的句柄(DIR*、FILE*)都必须在使用后正确关闭,glob_t 必须用 globfree() 释放,否则会造成资源泄漏,长期运行的程序尤其需要注意。
你在 Linux C 文件操作中,还遇到过哪些结构体相关的坑?欢迎在评论区分享你的经验,我们一起交流进步。
水平有限,欢迎大家交流指正,共同进步。




