我想通过 C 程序获得 linux 中特定目录的确切大小。我尝试使用 statfs(path,struct statfs &) 但它没有给出确切的大小。我也尝试使用 stat() 但它返回任何 dir 的大小为 4096 !
请建议我如何获得 dir 的确切大小,就像我们在“du -sh dirPath”命令之后获得的一样。
我也不想通过 system() 使用 du。
提前致谢。
典型解决方案
如果你想要一个目录的大小,类似于 du,创建一个递归函数。可以迭代地解决该问题,但该解决方案适用于递归。
信息
这是一个帮助您入门的链接:
http://www.cs.utk.edu/~plank/plank/classes/cs360/360/notes/Prsize/lecture.html
搜索
使用“stat c program recursive directory size”搜索 Google
例子
直接来自 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'
'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");
}
}
}
我想该解决方案可能对那些仍然可能遇到问题的人有用。
这是为模仿linuxdu
程序而编写的函数。它递归地遍历所有目录并累加文件大小。
请注意,此功能仍然不完整,因为它在硬链接上的行为不正确。应该添加一个容器来存储指向同一个 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;
}