5

我想通过 C 程序获得 linux 中特定目录的确切大小。我尝试使用 statfs(path,struct statfs &) 但它没有给出确切的大小。我也尝试使用 stat() 但它返回任何 dir 的大小为 4096 !

请建议我如何获得 dir 的确切大小,就像我们在“du -sh dirPath”命令之后获得的一样。

我也不想通过 system() 使用 du。

提前致谢。

4

4 回答 4

10

典型解决方案

如果你想要一个目录的大小,类似于 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);
}
于 2009-07-15T05:17:52.830 回答
4

您需要 stat() 当前目录和子目录中的所有文件并将它们添加起来。

考虑为此使用递归算法。

于 2009-07-15T05:13:03.183 回答
2

如果您不想使用,'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");
    }
  }
}
于 2011-07-21T16:30:29.720 回答
0

我想该解决方案可能对那些仍然可能遇到问题的人有用。

这是为模仿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;
}
于 2017-05-16T17:05:50.917 回答