2009-07-15 15 views
2

C 프로그램을 통해 리눅스에서 특정 디렉토리의 정확한 크기를 얻고 싶습니다. statfs (path, struct statfs &)를 사용했지만 정확한 크기를 제공하지 않았습니다. 또한 stat()로 시도했지만 모든 dir에 대해 4096으로 크기를 반환합니다!리눅스에서 프로그래밍 방식으로 dir의 크기를 얻는 방법은 무엇입니까?

"du -sh dirPath"명령을 사용하는 것과 같이 정확한 크기의 dir을 얻을 수있는 방법을 제안하십시오.

또한 나는 du (시스템)를 사용하고 싶지 않습니다.

미리 감사드립니다.

+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'

예 : 여기에 정보

당신이 시작하는 링크입니다

직접 짐 플랭크 (Jim Plank) 웹 사이트에서 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

, 당신은, 새로운 프로세스를 포크, 파이프를 구축 파이프, 간부에 아이의 '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; 
}