getdents64系统调用及示例

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"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值