温馨提示×

linux readdir如何遍历

小樊
43
2026-09-11 14:16:59
栏目: 智能运维

在 Linux 下,readdir 是用来遍历目录的标准 POSIX 接口,通常和 opendir / closedir 配合使用。下面从基本用法 → 示例 → 注意事项给你讲清楚。


一、基本流程

#include <dirent.h>
#include <stdio.h>

DIR *dir = opendir(path);   // 打开目录
if (!dir) { perror("opendir"); return; }

struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
    // 处理 entry->d_name
}

closedir(dir);              // 关闭目录

二、核心函数说明

1. opendir

DIR *opendir(const char *name);
  • 成功返回 DIR*
  • 失败返回 NULL

2. readdir

struct dirent *readdir(DIR *dirp);
  • 每次调用返回一个目录项
  • 返回 NULL 表示结束或出错
struct dirent {
    ino_t          d_ino;
    off_t          d_off;
    unsigned short d_reclen;
    unsigned char  d_type;
    char           d_name[256];
};

常用字段:

  • d_name:文件名
  • d_type:文件类型(可选):
    • DT_REG 普通文件
    • DT_DIR 目录
    • DT_LNK 符号链接

3. closedir

int closedir(DIR *dirp);

三、完整示例:遍历目录

#include <stdio.h>
#include <dirent.h>

int main(int argc, char *argv[]) {
    const char *path = argc > 1 ? argv[1] : ".";

    DIR *dir = opendir(path);
    if (!dir) {
        perror("opendir");
        return 1;
    }

    struct dirent *entry;
    while ((entry = readdir(dir)) != NULL) {
        printf("%s\n", entry->d_name);
    }

    closedir(dir);
    return 0;
}

编译运行:

gcc readdir_demo.c -o readdir_demo
./readdir_demo /tmp

四、递归遍历目录(常见需求)

#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>

void list_dir(const char *path) {
    DIR *dir = opendir(path);
    if (!dir) return;

    struct dirent *entry;
    while ((entry = readdir(dir)) != NULL) {
        if (strcmp(entry->d_name, ".") == 0 ||
            strcmp(entry->d_name, "..") == 0)
            continue;

        char full[1024];
        snprintf(full, sizeof(full), "%s/%s", path, entry->d_name);
        printf("%s\n", full);

        if (entry->d_type == DT_DIR) {
            list_dir(full);
        }
    }
    closedir(dir);
}

int main() {
    list_dir(".");
    return 0;
}

⚠️ 注意:某些文件系统 d_type 可能不可用,需用 stat() 判断类型


五、常见坑点

1. ... 会包含

必须手动跳过,否则递归会死循环

2. readdir 不是线程安全的

线程安全版本:

int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);

(已逐步废弃,推荐 readdir + 单线程或加锁)

3. 文件名长度

d_name 是变长数组,不要越界拷贝


六、和 scandir 的区别(补充)

如果你想排序 / 过滤

scandir(path, &namelist, filter, alphasort);

更方便,但会一次性加载全部目录项。


如果你需要:

  • 只遍历普通文件
  • 按修改时间排序
  • C++ / Rust / Python 版本
  • 底层 getdents 实现

可以直接说,我给你对应示例。

0