getdents64 函数详解
1. 函数介绍
getdents64 是 Linux 系统中用于读取目录内容的底层系统调用。可以把这个函数想象成一个"目录内容扫描仪"——它能够高效地扫描目录中的所有文件和子目录,就像超市的扫描枪快速读取商品条码一样。
与高级的目录操作函数(如 readdir)不同,getdents64 是最底层的接口,直接与内核交互,提供了最大的灵活性和性能。它返回的是原始的目录项数据,包含文件名、inode 号、文件类型等信息。
2. 函数原型
#include <dirent.h> /* 或者 <unistd.h> */
#include <sys/syscall.h>
int getdents64(unsigned int fd, struct linux_dirent64 *dirp, unsigned int count);
3. 功能
getdents64 函数用于从已打开的目录文件描述符中读取目录项(directory entries)。它一次可以读取多个目录项,比逐个读取效率更高。
4. 参数
- fd: 已打开的目录文件描述符(通过
open()或opendir()获得) - dirp: 指向缓冲区的指针,用于存储读取的目录项数据
- count: 缓冲区的大小(以字节为单位)
5. struct linux_dirent64 结构体
struct linux_dirent64 {
ino64_t d_ino; /* 64位 inode 号 */
off64_t d_off; /* 到下一个目录项的偏移 */
unsigned short d_reclen; /* 此目录项的长度 */
unsigned char d_type; /* 文件类型 */
char d_name[]; /* 文件名(以 null 结尾) */
};
6. 文件类型(d_type 字段)
| 类型值 | 宏定义 | 说明 |
|---|---|---|
| 0 | DT_UNKNOWN | 未知类型 |
| 1 | DT_FIFO | 命名管道 |
| 2 | DT_CHR | 字符设备 |
| 4 | DT_DIR | 目录 |
| 6 | DT_BLK | 块设备 |
| 8 | DT_REG | 普通文件 |
| 10 | DT_LNK | 符号链接 |
| 12 | DT_SOCK | 套接字 |
7. 返回值
- 成功: 返回实际读取的字节数(0 表示到达目录末尾)
- 失败: 返回 -1,并设置相应的 errno 错误码
常见错误码:
EBADF: fd 不是有效的目录文件描述符EFAULT: dirp 指针无效EINVAL: 参数无效ENOENT: 目录不存在
8. 相似函数或关联函数
- getdents: 旧版本的目录读取函数(32位 inode)
- readdir: POSIX 标准的目录读取函数(更高级的接口)
- opendir/fdopendir: 打开目录
- closedir: 关闭目录
- scandir: 扫描目录并排序
- ls: 命令行目录列表工具
9. 示例代码
示例1:基础用法 - 读取目录内容
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/syscall.h>
#include <dirent.h>
#include <string.h>
// 目录项结构体(64位版本)
struct linux_dirent64 {
ino64_t d_ino; /* Inode number */
off64_t d_off; /* Offset to next structure */
unsigned short d_reclen; /* Size of this structure */
unsigned char d_type; /* File type */
char d_name[]; /* Filename (null-terminated) */
};
// 获取文件类型字符串
const char* get_file_type_string(unsigned char d_type) {
switch (d_type) {
case DT_REG: return "普通文件";
case DT_DIR: return "目录";
case DT_LNK: return "符号链接";
case DT_CHR: return "字符设备";
case DT_BLK: return "块设备";
case DT_FIFO: return "命名管道";
case DT_SOCK: return "套接字";
case DT_UNKNOWN:
default: return "未知";
}
}
// 获取文件类型字符
char get_file_type_char(unsigned char d_type) {
switch (d_type) {
case DT_REG: return 'f';
case DT_DIR: return 'd';
case DT_LNK: return 'l';
case DT_CHR: return 'c';
case DT_BLK: return 'b';
case DT_FIFO: return 'p';
case DT_SOCK: return 's';
case DT_UNKNOWN:
default: return '?';
}
}
int main(int argc, char *argv[]) {
int fd;
char buf[4096];
int nread;
char *dir_path;
// 获取目录路径参数
if (argc != 2) {
printf("用法: %s <目录路径>\n", argv[0]);
dir_path = "."; // 默认当前目录
printf("使用当前目录: %s\n\n", dir_path);
} else {
dir_path = argv[1];
}
// 打开目录
fd = open(dir_path, O_RDONLY | O_DIRECTORY);
if (fd == -1) {
perror("open");
return 1;
}
printf("=== 目录 '%s' 的内容 ===\n", dir_path);
printf("%-12s %-10s %-8s %s\n", "INODE", "类型", "大小", "名称");
printf("%-12s %-10s %-8s %s\n"

最低0.47元/天 解锁文章
1966

被折叠的 条评论
为什么被折叠?



