2009-07-15 23 views
2

私はLinuxの特定のディレクトリの正確なサイズをCプログラムで取得したいと考えています。 私はstatfs(path、struct statfs &)を使ってみましたが、正確なサイズは与えていません。 私はstat()でも試しましたが、任意のdirに対して4096というサイズを返します!Linuxのプログラムでディレクトリのサイズを取得する方法は?

"du -sh dirPath"コマンドのように、私はdirの正確なサイズを取得する方法を提案してください。

また、私はduを通してsystem()を使用したくありません。

ありがとうございます。

+1

ディスク使用量(du)とファイルサイズの合計(stat)は同じではありません。どちらがいいですか?ディレクトリ上の –

+0

statは、ファイルサイズの合計を返しません。ディレクトリ上のstatは、ディレクトリエントリ自身が使用する領域の量を返します。 – derobert

答えて

4

現在のディレクトリとサブディレクトリ内のすべてのファイルをstat()して追加する必要があります。

このために再帰アルゴリズムを使用することを検討してください。

6

典型的なソリューション

あなたはデュとファッションに似たディレクトリのサイズを、必要な場合は、再帰関数を作成します。反復的に問題を解決することは可能ですが、解決策は再帰に役立ちます。

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

検索

Search Google with 'stat c program recursive directory size'

例:ここでは

情報

は、あなたが始めるためのリンクです

ジム・プランクのウェブサイトから直接、an exampleとしてご利用ください。あなたが'system'を使用したいが、'pipe''fork''execlp''du'を使用しても大丈夫ですしていない場合

#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); 
} 
+1

再帰的に行う必要はありませんが、ディレクトリを横断的に繰り返し実行することもできます; –

+0

de-> d_nameには、絶対パスではなくディレクトリ内のノード名だけが含まれます。 –

2

、あなたは、新しいプロセスをフォーク、パイプを構築パイプ、execの中で子供の'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"); 
    } 
    } 
} 
0

解決策は、問題がまだ発生する可能性がある人には便利だと思います。

ここには、Linux duプログラムを模倣するために書かれた機能があります。それは再帰的にすべてのディレクトリを通過し、ファイルサイズを追加します。

注:注:この関数はハードリンクで正しく動作しないため、この関数はまだ不完全です。同じiノードエンティティを指すファイル記述子を格納するコンテナを追加し、それを使用して非常に同じファイルの複数のカウントを取り除く必要があります。 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; 
} 
関連する問題