как получить размер каталога программно в Linux? - PullRequest
3 голосов
/ 15 июля 2009

Я хочу получить точный размер определенного каталога в linux через программу на Си. Я пытался использовать statfs (path, struct statfs &), но он не дает точного размера. Я также пытался с stat (), но он возвращает размер как 4096 для любого каталога!

Пожалуйста, предложите мне способ, которым я могу получить точный размер dir точно так же, как мы получаем после команды "du -sh dirPath".

Также я не хочу использовать du through system ().

Заранее спасибо.

Ответы [ 4 ]

8 голосов
/ 15 июля 2009

Типичное решение

Если вы хотите, чтобы размер директории, аналогичный моде du, создайте рекурсивную функцию. Можно решить проблему итеративно, но решение поддается рекурсии.

Информация

Вот ссылка, с которой можно начать:

http://www.cs.utk.edu/~plank/plank/classes/cs360/360/notes/Prsize/lecture.html

Поиск

Поиск в Google по 'рекурсивному размеру каталога stat c программы'

Пример * +1026 *

Непосредственно с веб-сайта Джима Планка, который служит примером для начала работы.

#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);
}
4 голосов
/ 15 июля 2009

Вам нужно выполнить stat () для всех файлов в текущем каталоге и подкаталогах и добавить их.

Рассмотрите возможность использования рекурсивного алгоритма для этого.

3 голосов
/ 21 июля 2011

Если вы не хотите использовать 'system', но можете использовать 'pipe', 'fork', 'execlp' и 'du', вы можете построить конвейер, создать новый процесс, перенаправить 'STDOUT' дочернего элемента в канале, exec '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");
    }
  }
}
0 голосов
/ 16 мая 2017

Я думаю, что решение может быть полезно для тех, кто все еще может столкнуться с проблемой.

Вот функция, написанная для имитации программы 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;
}
...