2011-02-06 17 views
0

私はCで新しく、現在の作業ディレクトリのすべてのディレクトリ/ファイルを再帰的に処理し、その情報を出力しようとしています。私が解決している良い方法について考えることができないという問題は、パスが2回目に間違って構築される同じディレクトリに2つのフォルダがある場合です。たとえば、 "/ something/dir1"の後にdir1とdir2が同じパスにある場合、パスは "/ something/dir2"になりますが、 "/ something/dir1/dir2"になります。私は以前のパスを把握していると思っていましたが、再帰呼び出しごとに常に書き直さなければ、それを行う方法がわかりません。Cのディレクトリを再帰

更新:私は元々のバグを修正して、ここに新しいコードを投稿すると考えました。 opendir( "。")とchangedir( "..")は、私が気付いていなかったトリックは実際にはその期間を完全な現在または前のパスに変換します。 type = 8とtype = 4ステートメントをより読みやすいS_ISDIR(statbuf.st_mode)ステートメントとS_ISREG(statbuf.st_mode)ステートメントに変更する限り、それらは型ステートメントでは機能しません。文法と私がそれらを使って試した方法に何が間違っているか分からない。

アップデート2:私はここS_ISDIR/S_ISREGの問題を解決 - How to use S_ISREG() and S_ISDIR() POSIX Macros?

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

void helper(DIR *, struct dirent *, struct stat, char *, int); 
void dircheck(DIR *, struct dirent *, struct stat, char *, int); 

int main(int argc, char *argv[]){ 

    DIR *dip; 
    struct dirent *dit; 
    struct stat statbuf; 
    char currentPath[FILENAME_MAX]; 
    int depth = 0; /*Used to correctly space output*/ 

    dip = opendir("."); 
    getcwd(currentPath, FILENAME_MAX); 

    while((dit = readdir(dip)) != NULL){ 

    /*Skips . and ..*/ 
    if(strcmp(dit->d_name, ".") == 0 || strcmp(dit->d_name, "..") == 0) 
     continue; 

    stat(currentPath, &statbuf); 

    /*Checks if current item is of the type file (type 8)*/ 
    if(dit->d_type == 8) 
     printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size); 

    /*Checks if current item is of the type directory (type 4)*/ 
    if(dit->d_type == 4) 
     dircheck(dip, dit, statbuf, currentPath, depth); 

    } 
    return 0; 
} 

/*Recursively called helper function*/ 
void helper(DIR *dip, struct dirent *dit, struct stat statbuf, char currentPath[FILENAME_MAX], int depth){ 
    int i = 0; 
    dip = opendir(currentPath); 

    while((dit = readdir(dip)) != NULL){ 

    if(strcmp(dit->d_name, ".") == 0 || strcmp(dit->d_name, "..") == 0) 
     continue; 

    stat(currentPath, &statbuf); 

    if(dit->d_type == 8){ 
     for(i = 0; i < depth; i++) 
     printf(" "); 
     printf("%s (%d bytes)\n", dit->d_name, (int)statbuf.st_size); 
    } 

    if(dit->d_type == 4) 
     dircheck(dip, dit, statbuf, currentPath, depth); 

    } 
} 

void dircheck(DIR *dip, struct dirent *dit, struct stat statbuf, char currentPath[FILENAME_MAX], int depth){ 
    int i = 0; 

    strcat(currentPath, "/"); 
    strcat(currentPath, dit->d_name); 

    /*If two directories exist at the same levelt the path 
    is built wrong and needs to be corrected*/ 
    if((chdir(currentPath)) == -1){ 
    chdir(".."); 
    getcwd(currentPath, FILENAME_MAX); 
    strcat(currentPath, "/"); 
    strcat(currentPath, dit->d_name); 

    for(i = 0; i < depth; i++) 
     printf (" "); 
    printf("%s (subdirectory)\n", dit->d_name); 
    depth++; 
    helper(dip, dit, statbuf, currentPath, depth); 
    } 

    else{ 
    for(i =0; i < depth; i++) 
     printf(" "); 
    printf("%s (subdirectory)\n", dit->d_name); 
    chdir(currentPath); 
    depth++; 
    helper(dip, dit, statbuf, currentPath, depth); 
    } 

} 
+1

あなた自身の質問に既に回答しているようです... –

+1

@Oli:再読み込み。 OPは現在のコードにバグがあると言いました。また、これはヒープ上にたくさんのメモリを割り当てる(またはさらに悪いことに、スタック上で)代わりに、できるだけ再帰の各レベルで既存のバッファを最良に再利用する方法を学ぶ非常に有用な学習の練習になります。 –

+0

'type == 8'? 'readdir'マンページのシンボル定数には理由があります。 – asveikau

答えて

4

を不車輪の再発明をしないでください。場合は、一方

http://pubs.opengroup.org/onlinepubs/9699919799/functions/nftw.html

:あなたはunixyシステムにしている場合は、nftwライブラリ関数あなたが望むものを正確に行います(POSIXでXSIのオプショングループの一部では、それはほとんど一般利用可能だという意味します)学習の練習としてこれをやっている場合、またはnftwが(複数のスレッドから同時にディレクトリ再帰を実行する必要がある場合など)、あなたのソリューションをデバッグするために進んでいる場合など、これに

if(type == 4) 

if(S_ISDIR(statbuf.st_mode)) 

は詳細についてstat manpageを参照してください

+0

私はシステムコールで学習の練習としてそれ以上のことをしていますが、このライブラリについて私に知らせてくれてありがとう。私はこの機能を将来必要とするなら、間違いなくそれを使用します。 – zalberico

1

私はどうしたら非常に最初のものは、これを変更しています。

第2に、決してclosedirに電話していないようです。あなたはものを解放する必要があります。

第3回opendir/readdirコードを2か所にコピーして貼り付けるのではなく、この冗長な作業を同じ機能に置くことが重要です。

最後に、それぞれの再帰でスタックにMAX_PATHを割り当てることはかなり大きくなります。 mallocreallocを使用するとよいでしょう。しかし、@ R ..上で言及したように、可能な限り、これらのバッファを再利用しようとするべきです。大きなdirツリーの場合、これは多くのスペースを使用し、高価になります。

+0

ありがとう、これらは参考になる変更です。どのように私はバグを解決することができます任意のアイデア? – zalberico

+0

readdirコードが別の関数にない理由は、現在のバグが原因です。これは、最初のパスで複数のディレクトリで動作する理由である、メインで再構築できるパスでした。より深いレベルに再帰して問題になるのです。前のパスを保存しようとすると、再帰呼び出しが行われるたびに上書きされると考えることができません。 – zalberico

関連する問題