2011-12-31 2 views
3

Я пытаюсь написать базовую программу, которая суммирует файлы всех файлов в текущем каталоге и во всех подкаталогах. Я думал, что это будет отличное упражнение. Я пытаюсь использовать базовую рекурсию для этого. Вот то, что я до сих пор:Написание простой клон. Получение случайных значений для файлов в подкаталогах.

#include <stdio.h> 
#include <sys/stat.h> 
#include <sys/types.h> 
#include <dirent.h> 
#include <string.h> 

long totalbytes = 0; 

long dirsize(const char* directory, int verbose) 
{ 
    struct dirent *de; 
    struct stat s; 
    DIR * dir; 
    //long total_items = 0; 
    long filesize = 0; 

    dir = opendir(directory); 
    if (dir == NULL) 
    { 
    printf("Failed to open %s.\n", directory); 
    return -1; 
    } 

    while ((de = readdir (dir)) != NULL) 
    { 
    stat(de->d_name, &s); 
    if (S_ISLNK(s.st_mode)) 
    { 
    printf("links are ignored.\n"); 
    } 
    if (de->d_type == DT_REG) 
    { 
    filesize = 0; //be sure to reset this each time to avoid inaccuracy 
    stat(de->d_name, &s); // get file info into our s structure 
    if (verbose) 
    { 
     printf("%s/%s : %ld bytes (%f MB)\n", directory, de->d_name, s.st_size, (float) s.st_size/1024/1024); 
    } 
    filesize = s.st_size; //put file size into filesize variable 
    totalbytes += filesize; //increment totalbytes 
    } 
    if (de->d_type == DT_DIR && strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0) 
    { 
    char pathname[PATH_MAX]; 
    sprintf(pathname, "%s/%s", directory, de->d_name); 
    dirsize(pathname, verbose); //recursion: keep looping until no more subdirs remain 
    } 
    } 
    closedir(dir); 
    return totalbytes; 
} 

long compute_size(const char* directory, int verbose) 
{ 
    long space = dirsize(directory, verbose); 
    return space; 
} 

int main(int argc, char* argv[]) 
{ 
    if (argc != 2) 
    { 
    printf("Usage: dirsize DIRECTORY\n"); 
return -1; 
    } 

    int verbose = 1; //show or hide individual computations 

    long space = compute_size(argv[1], verbose); 
    if (space != -1) 
    { 
    float space_mb = (float) space/1024/1024; 
    printf("space occupied: %ld bytes\n", space); 
    printf("(%f MB)\n", space_mb); 
    } 
    return 0; 
} 

Вот мой вывод программы (я также с включением в Ls поддиректории)

08:35 [email protected]~/tmp$ ./dirsize . 
./dirsize : 8369 bytes (0.007981 MB) 
./diskstat.c : 1430 bytes (0.001364 MB) 
./diskstat : 7993 bytes (0.007623 MB) 
./ftw.c : 491 bytes (0.000468 MB) 
./a.out : 8044 bytes (0.007671 MB) 
./arrays.sh : 212 bytes (0.000202 MB) 
./fileread/timestamp : 0 bytes (0.000000 MB) 
./fileread/timestamp.c : 0 bytes (0.000000 MB) 
./fileread/a.out : 8044 bytes (0.007671 MB) 
./fileread/build.prop : 8044 bytes (0.007671 MB) 
./fileread/read.c : 4096 bytes (0.003906 MB) 
./fileread/read : 454656 bytes (0.433594 MB) 
./local.fstab : 76 bytes (0.000072 MB) 
./dirsize.c : 1857 bytes (0.001771 MB) 
./echo.sh : 223 bytes (0.000213 MB) 
./TEAMS.sh : 605 bytes (0.000577 MB) 
space occupied: 504140 bytes 
(0.480785 MB) 
08:35 [email protected]~/tmp$ ls -l fileread/ 
total 40 
-rwxr-xr-x 1 raidzero raidzero 8132 Dec 28 10:39 a.out 
-rw-r--r-- 1 raidzero raidzero 2346 Dec 28 10:09 build.prop 
-rwxr-xr-x 1 raidzero raidzero 8384 Dec 29 13:57 read 
-rw-r--r-- 1 raidzero raidzero 1150 Dec 28 10:16 read.c 
-rwxr-xr-x 1 raidzero raidzero 8132 Dec 29 13:57 timestamp 
-rw-r--r-- 1 raidzero raidzero 659 Dec 28 10:39 timestamp.c 
08:35 [email protected]~/tmp$ 

В моем ограниченном опыте, получение случайных данных является признаком неправильного выделение памяти, но st_size в структуре stat является длинным int ..?

+0

Посмотрите на ['nftw()'] (http://pubs.opengroup.org/onlinepubs/9699919799/functions/nftw.html), чтобы упростить некоторые части вашей работы. –

+0

Обратите внимание, что 'stat (de-> d_name, &s); if (S_ISLNK (s.st_mode))' никогда не обнаружит символическую ссылку, вы должны использовать 'lstat()', чтобы увидеть ссылку как ссылку. ('Stat() 'следует символической ссылке на свой горький конец,' lstat() 'говорит, что запись является символической ссылкой, если она есть, и в противном случае ведет себя как' stat() '. –

+0

Было бы разумно использовать' snprintf() 'для объединения каталог и имя файла, что предотвращает переполнение буфера.Конечно, вам также нужно проверить, завершено ли копирование. –

ответ

2

de->d_name только имеет имя файла - оно не содержит путь, ведущий к нему. Например, вы ставите ./timestamp, а не ./fileread/timestamp. Вы можете либо построить полный путь к файлу, либо использовать chdir() для ввода каталогов по ходу дела (небезопасно, если вы находитесь в многопоточной среде и можете быть хрупкими, если каталоги перемещаются, когда вы в них находитесь - fchdir() может быть очень полезным, чтобы вернуться к более высоким каталогам), или (в недавнем unixen) используют функции /fstat() для перемещения по каталогам.

Обратите внимание, что, если бы вы проверили ошибки, возвращаемые с stat, вы бы это заметили. Всегда проверяйте эти ошибки.

+0

Я использовал sprintf для создания пути к файлу, хотя здесь: 'sprintf (pathname,"% s /% s ", directory, de-> d_name);' (по крайней мере, это было мое намерение) – raidzero

+0

Я проверю коды возврата, хороший совет: D – raidzero

+0

@raidzero, вы делаете это, когда вы рекурсируете в подкаталоги, но вы вызываете stat на raw 'de-> d_name' значение – bdonlan

 Смежные вопросы

  • Нет связанных вопросов^_^