首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

C語言遍歷文件與目錄完整實現:遞歸深度優先、統計計數、跨平台兼容

     編輯:關於C

核心代碼(Linux/POSIX)


#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define MAX_PATH 512

unsigned long dir_count = 0, file_count = 0;

void listdir(const char *path) {
    DIR *dp = opendir(path);
    if (!dp) {
        perror("opendir");
        return;
    }

    struct dirent *entry;
    char child_path[MAX_PATH];
    char file_path[MAX_PATH];

    while ((entry = readdir(dp)) != NULL) {
        // 跳過 . 和 ..
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
            continue;

        // 構建完整路徑
        snprintf(child_path, MAX_PATH, "%s/%s", path, entry->d_name);

        if (entry->d_type == DT_DIR) {
            printf("[DIR]  %s\n", child_path);
            dir_count++;
            listdir(child_path); // 遞歸遍歷子目錄
        } else if (entry->d_type == DT_REG) {
            snprintf(file_path, MAX_PATH, "%s/%s", path, entry->d_name);
            printf("[FILE] %s\n", file_path);
            file_count++;
        }
        // 其他類型(符號鏈接、設備文件等)可按需擴展
    }

    closedir(dp);
}

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: %s \n", argv[0]);
        return 1;
    }

    listdir(argv[1]);
    printf("\nTotal DIRs: %lu, Total FILEs: %lu\n", dir_count, file_count);
    return 0;
}

關鍵 API 解析

d_type 可移植性補充

部分文件系統/內核版本不支持 d_type(返回 DT_UNKNOWN)。通用做法:


struct stat st;
stat(full_path, &st);
if (S_ISDIR(st.st_mode)) { /* 目錄 */ }
else if (S_ISREG(st.st_mode)) { /* 普通文件 */ }

雖多一次系統調用,但完全可移植。

Windows 版本(_findfirst/_findnext)


#ifdef _WIN32
#include 
void listdir_win(const char *path) {
    char search_path[MAX_PATH];
    snprintf(search_path, MAX_PATH, "%s\\*", path);
    
    struct _finddata_t fd;
    intptr_t handle = _findfirst(search_path, &fd);
    if (handle == -1) return;

    do {
        if (strcmp(fd.name, ".") == 0 || strcmp(fd.name, "..") == 0) continue;
        char full_path[MAX_PATH];
        snprintf(full_path, MAX_PATH, "%s\\%s", path, fd.name);
        if (fd.attrib & _A_SUBDIR) {
            printf("[DIR]  %s\n", full_path);
            dir_count++;
            listdir_win(full_path);
        } else {
            printf("[FILE] %s\n", full_path);
            file_count++;
        }
    } while (_findnext(handle, &fd) == 0);
    _findclose(handle);
}
#endif

增強功能:文件過濾、大小統計、深度限制


typedef struct {
    const char *ext_filter; // 如 ".c", NULL 為不限
    int max_depth;          // -1 無限制
    unsigned long total_size;
} WalkConfig;

void listdir_ex(const char *path, int depth, WalkConfig *cfg) {
    if (cfg->max_depth >= 0 && depth > cfg->max_depth) return;
    // ... 遍歷邏輯 ...
    if (entry->d_type == DT_REG) {
        struct stat st;
        stat(full_path, &st);
        if (!cfg->ext_filter || strstr(entry->d_name, cfg->ext_filter))
            cfg->total_size += st.st_size;
    }
}

最佳實踐總結

  1. 錯誤處理:opendir/stat/malloc 必須檢查返回值。
  2. 資源管理:closedir、_findclose、free 嚴格配對。
  3. 緩衝區安全:使用 snprintf、PATH_MAX (limits.h) 替代固定大小。
  4. 符號鏈接保護:避免循環鏈接導致無限遞歸,記錄已訪問 inode (stat.st_ino) 或限制深度。
  5. 權限錯誤靜默跳過:opendir 失敗僅打印警告繼續,不中斷整個遍歷。
  6. 大目錄性能:考慮 fts (BSD) 或 nftw (POSIX) 替代手寫遞歸,支持並發、排序、過濾。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
函數/結構作用備註
opendir打開目錄流返回 DIR*,失敗返回 NULL
readdir讀取下一個目錄項返回 struct dirent*,結束返回 NULL
closedir關閉目錄流必須調用,否則洩漏文件描述符
struct dirent目錄項結構d_name 文件名,d_type 類型 (DT_DIR/DT_REG/DT_LNK...)
snprintf安全格式化路徑防止緩衝區溢出,替代 sprintf