如何递归遍历文件夹并统计文件总大小?代码实现遇阻求助
解决递归文件夹文件大小统计问题
嘿,我来帮你搞定这个文件大小统计的问题!你现在遇到两个核心困扰:非递归模式下统计结果不准,还有递归遍历文件夹的逻辑没捋顺。咱们一步步拆解解决:
先排查非递归统计不准的原因
非递归统计出错,大概率是踩了这几个坑:
- 没跳过
.和..这两个特殊目录项,导致重复统计或者逻辑混乱 - 误把目录本身的大小算进了总文件大小(目录也是一种文件,但我们要统计的是它内部的文件)
- 没区分
stat()和lstat()的差异:stat()会跟随符号链接到目标文件,lstat()只统计链接本身的大小,选不对就会出现大小偏差 - 缺少错误处理:比如某个文件/目录无法访问时直接跳过,没做任何处理,导致统计遗漏
递归逻辑的核心实现思路
递归遍历的逻辑其实很清晰,就是「遇到目录就进去重复当前操作」:
- 打开目标目录,获取目录句柄
- 遍历目录下的每个条目
- 对每个条目做判断:
- 如果是普通文件:调用
stat()/lstat()获取大小,累加到总大小 - 如果是目录(且不是
./..):递归调用同一个统计函数处理这个子目录,把返回的子目录总大小加进来
- 如果是普通文件:调用
- 遍历结束后关闭目录句柄,返回累加的总大小
完整可运行的示例代码
下面是包含递归逻辑、错误处理,且能准确统计的完整代码:
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <dirent.h> #include <string.h> #include <errno.h> #include <limits.h> // 包含PATH_MAX定义 // 递归计算目录及其子目录下所有普通文件的总大小 off_t calculate_total_size(const char *path) { off_t total = 0; DIR *dir = opendir(path); // 处理目录打开失败的情况 if (!dir) { fprintf(stderr, "⚠️ 无法打开目录 %s: %s\n", path, strerror(errno)); return 0; } struct dirent *entry; while ((entry = readdir(dir)) != NULL) { // 跳过当前目录和上级目录,避免死循环和重复统计 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { continue; } // 拼接文件/子目录的完整路径 char full_path[PATH_MAX]; snprintf(full_path, sizeof(full_path), "%s/%s", path, entry->d_name); struct stat st; // 用lstat避免跟随符号链接,若需要统计链接指向的文件大小,替换为stat即可 if (lstat(full_path, &st) == -1) { fprintf(stderr, "⚠️ 无法获取文件信息 %s: %s\n", full_path, strerror(errno)); continue; } if (S_ISREG(st.st_mode)) { // 普通文件,累加大小 total += st.st_size; } else if (S_ISDIR(st.st_mode)) { // 子目录,递归计算其内部文件总大小 total += calculate_total_size(full_path); } // 若需要统计其他类型文件(比如符号链接、设备文件),可添加对应的判断分支 } closedir(dir); return total; } int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "用法: %s <目标目录路径>\n", argv[0]); return 1; } off_t total_size = calculate_total_size(argv[1]); printf("✅ 总文件大小: %lld 字节\n", (long long)total_size); return 0; }
关键细节说明
- 路径拼接:用
snprintf和PATH_MAX确保路径不会溢出,避免内存错误 - 错误处理:每个系统调用(
opendir、lstat)都做了错误捕获,避免程序崩溃,同时给出明确的错误提示 - 符号链接处理:默认用
lstat统计链接本身,若需要统计链接指向的文件,替换为stat即可 - 非递归修正:如果要改成非递归版本,只需要把递归调用换成用栈/队列存储待处理的目录路径,逻辑和递归一致,只是用循环代替函数递归
内容的提问来源于stack exchange,提问作者user9443617
相关产品推荐
相关产品推荐

