服务器测评网
我们一直在努力

Linux C如何遍历文件夹下所有文件及子文件夹?

在Linux系统中,使用C语言遍历文件夹下的所有文件是一项常见的操作,尤其在系统编程、文件管理工具开发等场景中应用广泛,要实现这一功能,需要深入理解Linux的文件系统接口和目录操作机制,本文将详细介绍如何通过C语言递归或非递归地遍历目录,并涵盖关键的系统调用、错误处理以及代码实现细节。

20251110021254176271197425689

目录操作基础:opendir与readdir

在Linux中,遍历目录的核心是<dirent.h>头文件中提供的函数族。opendir()函数用于打开一个目录流,返回DIR*指针,类似于打开文件时返回的FILE*,若目录打开成功,可结合readdir()函数逐个读取目录项。readdir()返回一个struct dirent结构体指针,其中包含文件名、文件类型等信息,当读取到目录末尾时,readdir()返回NULL

以下是一个简单的非递归遍历示例:

#include <dirent.h>
#include <stdio.h>
void traverse_directory(const char *path) {
    DIR *dir = opendir(path);
    if (dir == NULL) {
        perror("opendir failed");
        return;
    }
    struct dirent *entry;
    while ((entry = readdir(dir)) != NULL) {
        if (entry->d_type == DT_REG) {
            printf("File: %s/%s\n", path, entry->d_name);
        }
    }
    closedir(dir);
}

上述代码仅遍历指定目录下的常规文件(DT_REG),若需处理子目录,则需要递归调用或结合其他方法。

递归遍历:深度优先搜索

若需遍历子目录中的所有文件,需采用递归方式,递归遍历的核心逻辑是:当遇到子目录(DT_DIR)时,排除和等特殊目录,然后递归调用遍历函数。

以下是递归遍历的实现:

20251110021255176271197537090

#include <sys/stat.h>
#include <string.h>
void recursive_traverse(const char *path) {
    DIR *dir = opendir(path);
    if (dir == NULL) {
        perror("opendir failed");
        return;
    }
    struct dirent *entry;
    char full_path[PATH_MAX];
    while ((entry = readdir(dir)) != NULL) {
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
        }
        snprintf(full_path, sizeof(full_path), "%s/%s", path, entry->d_name);
        struct stat statbuf;
        if (stat(full_path, &statbuf) == -1) {
            perror("stat failed");
            continue;
        }
        if (S_ISREG(statbuf.st_mode)) {
            printf("File: %s\n", full_path);
        } else if (S_ISDIR(statbuf.st_mode)) {
            recursive_traverse(full_path);
        }
    }
    closedir(dir);
}

此代码通过stat()函数获取文件状态,判断是否为目录(S_ISDIR),并递归处理,注意路径拼接时需考虑缓冲区溢出问题,使用snprintfsprintf更安全。

错误处理与健壮性

在实际应用中,错误处理至关重要,常见的错误场景包括:目录无权限打开、路径不存在、符号链接循环等。

  1. 权限检查:使用access()函数检查目录的可读权限,避免opendir()失败。
  2. 符号链接处理:若需解析符号链接,可使用realpath()获取真实路径,或使用stat()AT_SYMLINK_NOFOLLOW选项避免循环。
  3. 路径长度限制:Linux系统中PATH_MAX(通常为4096)定义了路径的最大长度,需确保拼接后的路径不超过此限制。

改进后的代码示例:

#include <unistd.h>
#include <limits.h>
if (access(path, R_OK) == -1) {
    perror("access denied");
    return;
}

性能优化:非递归实现

递归遍历在目录层级较深时可能导致栈溢出,此时可采用非递归方式,借助栈数据结构模拟递归过程,以下为伪代码逻辑:

  1. 初始化一个栈,将根目录压入栈中。
  2. 循环弹出栈顶目录,使用readdir()
  3. 若遇到子目录,则压入栈中。
  4. 直至栈为空,遍历结束。

非递归实现避免了递归的栈开销,适合处理深层目录结构,但需手动管理栈内存。

20251110021256176271197624253

完整示例:结合文件属性过滤

实际应用中,常需根据文件属性(如扩展名、大小、修改时间等)进行过滤,以下代码展示如何仅遍历.txt文件:

#include <fnmatch.h>
void filter_traverse(const char *path) {
    DIR *dir = opendir(path);
    if (dir == NULL) {
        perror("opendir failed");
        return;
    }
    struct dirent *entry;
    while ((entry = readdir(dir)) != NULL) {
        if (fnmatch("*.txt", entry->d_name, FNM_NOESCAPE) == 0) {
            printf("Text file: %s/%s\n", path, entry->d_name);
        }
    }
    closedir(dir);
}

fnmatch()函数支持通配符匹配,可用于灵活过滤文件。

使用C语言遍历Linux目录需综合运用opendir()readdir()stat()等系统调用,并根据需求选择递归或非递归方式,错误处理、路径安全性和性能优化是编写健壮代码的关键,通过合理设计,可实现高效、可靠的目录遍历功能,满足各类文件操作场景的需求。

赞(0)
未经允许不得转载:好主机测评网 » Linux C如何遍历文件夹下所有文件及子文件夹?