我想通过一个C程序来获得一个特定的dir的确切大小。 我尝试使用statfs(path,结构statfs&),但它没有给出确切的大小。 我也尝试了stat(),但它返回任何目录的大小为4096!
请告诉我,我可以通过“du -sh dirPath”命令来获得dir的确切大小。
另外我不想使用杜通过系统()。
提前致谢。
典型解决方案
如果你想要一个目录的大小,类似du的方式,创建一个递归函数。 迭代地解决这个问题是可能的,但是这个解决方案有助于递归。
信息
这里是一个链接,让你开始:
http://www.cs.utk.edu/~plank/plank/classes/cs360/360/notes/Prsize/lecture.html
搜索
搜索Google'stat c program递归目录大小'
例
直接来自Jim Plank的网站,作为一个例子 ,让你开始。
#include <stdio.h> #include <dirent.h> #include <sys/stat.h> main() { DIR *d; struct dirent *de; struct stat buf; int exists; int total_size; d = opendir("."); if (d == NULL) { perror("prsize"); exit(1); } total_size = 0; for (de = readdir(d); de != NULL; de = readdir(d)) { exists = stat(de->d_name, &buf); if (exists < 0) { fprintf(stderr, "Couldn't stat %s\n", de->d_name); } else { total_size += buf.st_size; } } closedir(d); printf("%d\n", total_size); }
您需要stat()当前目录和子目录中的所有文件并添加它们。
考虑使用递归算法。
如果你不想使用'system'
,但可以使用'pipe'
, 'fork'
, 'execlp'
和'du'
,你可以创建一个管道,fork一个新进程,重定向孩子的'STDOUT'
在管子里,小孩的父亲'du'
,并在父母的结果。 示例代码将是:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(void) { int pfd[2], n; char str[1000]; if (pipe(pfd) < 0) { printf("Oups, pipe failed. Exiting\n"); exit(-1); } n = fork(); if (n < 0) { printf("Oups, fork failed. Exiting\n"); exit(-2); } else if (n == 0) { close(pfd[0]); dup2(pfd[1], 1); close(pfd[1]); execlp("du", "du", "-sh", "/tmp", (char *) 0); printf("Oups, execlp failed. Exiting\n"); /* This will be read by the parent. */ exit(-1); /* To avoid problem if execlp fails, especially if in a loop. */ } else { close(pfd[1]); n = read(pfd[0], str, 1000); /* Should be done in a loop until read return 0, but I am lazy. */ str[n] = '\0'; close(pfd[0]); wait(&n); /* To avoid the zombie process. */ if (n == 0) { printf("%s", str); } else { printf("Oups, du or execlp failed.\n"); } } }
我想这个解决方案可能对那些仍然可能遇到问题的人有用。
这里是模仿linux du
程序写的功能。 它递归地遍历所有目录并添加文件大小。
请注意 ,此功能仍然不完整,因为它在硬链接上的行为不正确。 应该添加一个容器来存储指向同一个inode实体的文件描述符,并使用它来摆脱同一个文件的多个计数。 lstat()
用于处理符号链接(又名软链接), 硬链接是一个问题在这里 。
size_t countDiskUsage(const char* pathname) { if (pathname == NULL) { printf("Erorr: pathname is NULL\n"); } struct stat stats; if (lstat(pathname, &stats) == 0) { if (S_ISREG(stats.st_mode)){ return stats.st_size; } } else { perror("lstat\n"); } DIR* dir = opendir(pathname); if (dir == NULL) { perror("Error"); return 0; } struct dirent *dirEntry; size_t totalSize = 4096; for (dirEntry = readdir(dir); dirEntry != NULL; dirEntry = readdir(dir)) { long pathLength = sizeof(char) * (strlen(pathname) + strlen(dirEntry->d_name) + 2); char* name = (char*)malloc(pathLength); strcpy(name, pathname); strcpy(name + strlen(pathname), "/"); strcpy(name + strlen(pathname) + 1, dirEntry->d_name); if (dirEntry->d_type == DT_DIR) { if (strcmp(dirEntry->d_name, ".") != 0 && strcmp(dirEntry->d_name, "..") != 0) { totalSize += countDiskUsage(name); } } else { int status = lstat(name, &stats); if (status == 0) { totalSize += stats.st_size; } else { perror("lstat\n"); } } free(name); } closedir(dir); return totalSize; }