2009-06-11 27 views
12

ディレクトリツリーをスキャンし、各ディレクトリ内のすべてのファイルとフォルダを一覧表示したいと考えています。 Webカメラから画像をダウンロードしてローカルに保存するプログラムを作成しました。このプログラムは、画像がダウンロードされた時間に基づいてファイルツリーを作成します。私は今これらのフォルダをスキャンし、Webサーバーに画像をアップロードしたいが、私はどのように画像を見つけるためにディレクトリをスキャンすることができないのか分からない。 誰かがサンプルコードを投稿することができれば、非常に役に立ちます。C++での再帰的フォルダスキャン

編集: - 私は、組み込みLinuxシステム上でこれを実行すると、ブースト

+0

どのオペレーティングシステムですか? –

答えて

30

単純な「ファイルツリーウォーク」については、man ftwを参照してください。この例ではfnmatchも使用しました。

#include <ftw.h> 
#include <fnmatch.h> 

static const char *filters[] = { 
    "*.jpg", "*.jpeg", "*.gif", "*.png" 
}; 

static int callback(const char *fpath, const struct stat *sb, int typeflag) { 
    /* if it's a file */ 
    if (typeflag == FTW_F) { 
     int i; 
     /* for each filter, */ 
     for (i = 0; i < sizeof(filters)/sizeof(filters[0]); i++) { 
      /* if the filename matches the filter, */ 
      if (fnmatch(filters[i], fpath, FNM_CASEFOLD) == 0) { 
       /* do something */ 
       printf("found image: %s\n", fpath); 
       break; 
      } 
     } 
    } 

    /* tell ftw to continue */ 
    return 0; 
} 

int main() { 
    ftw(".", callback, 16); 
} 

(でもテストコンパイルが、あなたのアイデアを得るわけではありません。)

これはDIRENT sおよび再帰的なトラバースを自分で対処するよりもはるかに簡単です。


トラバーサルをより詳細に制御するには、ftsもあります。この例では、プログラムに開始点として明示的に渡されない限り、ドットファイル(名前が "。"で始まるファイルとディレクトリ)はスキップされます。

#include <fts.h> 
#include <string.h> 

int main(int argc, char **argv) { 
    char *dot[] = {".", 0}; 
    char **paths = argc > 1 ? argv + 1 : dot; 

    FTS *tree = fts_open(paths, FTS_NOCHDIR, 0); 
    if (!tree) { 
     perror("fts_open"); 
     return 1; 
    } 

    FTSENT *node; 
    while ((node = fts_read(tree))) { 
     if (node->fts_level > 0 && node->fts_name[0] == '.') 
      fts_set(tree, node, FTS_SKIP); 
     else if (node->fts_info & FTS_F) { 
      printf("got file named %s at depth %d, " 
       "accessible via %s from the current directory " 
       "or via %s from the original starting directory\n", 
       node->fts_name, node->fts_level, 
       node->fts_accpath, node->fts_path); 
      /* if fts_open is not given FTS_NOCHDIR, 
      * fts may change the program's current working directory */ 
     } 
    } 
    if (errno) { 
     perror("fts_read"); 
     return 1; 
    } 

    if (fts_close(tree)) { 
     perror("fts_close"); 
     return 1; 
    } 

    return 0; 
} 

また、コンパイルテストも実行テストもされていませんが、私はそれについて言及したいと思いました。

+0

FTSサンプルは素晴らしい結果を出しました。私がしなければならなかった唯一の変更は "ftsread" - > "fts_read"でした。そして、私はfts_readの結果を(FTSENT *)にキャストしなければなりませんでした。 このようなコードをWeb上で見つけるのは簡単だと思いましたが、これは間違いなく私が見つけた最もクリーンな例でした。 ありがとう! – Hortitude

+0

例をお寄せいただきありがとうございます。 –

+1

fts_infoの値は単一ビットではありません... options FTS_DからFTS_Wは、連続した値1から14として定義されています。コードをコメントなしで "&FTS_F"何が起きているのかを説明する。 FTS_F、FTS_INIT、FTS_NS、FTS_NSOK、FTS_SL、FTS_SLNONE、およびFTS_Wをここで取得しようとする可能性のある人です...しかし、FTS_NSまたはFTS_NSOKはちょっと奇妙です。また、Web上で "&FTS_D"というコードを見ていますが、これはほぼ確実に意図したものではありません(FTS_ERR、FTS_DEFAULTを取得します)。 – darron

6

Boost.Filesystemは、あなたがそれを行うことができますを使用するドント。 docsをチェックしてください!

EDIT:
Linuxを使用していて、Boostを使用したくない場合は、LinuxネイティブC関数を使用する必要があります。 This pageは、これを行う方法に関する多くの例を示しています。

+1

最後のリンクが壊れています –

0

Qt/Embeddedを使用できるのであれば、 というQDirとQFileInfoクラスがありますが、Qtを使用できるかどうかによって異なります。問題は、あなたのシステムが提供するAPIです。

1

dirent.hで宣言されているディレクトリ関数を使用すると便利です。このwikipedia pageには、サンプルコードが記載されています。アプリケーションでは、ディレクトリを特定したら、処理関数を再帰的に呼び出して、ディレクトリの内容を処理する必要があります。

1

glob/globfreeも使用できます。

+0

ディレクトリを読み込んで自分でマッチを実行するが、それでも再帰的ではない方が簡単です。確かに、GLOB_ONLYDIRを使うと、DIRENTを完全に扱うことはできませんが、それでもftwと同じくらい便利ではありません。純粋に名前ベースのトラバーサルは大変です。 – ephemient

2

私は古い学校ですが、私にとってはftw()です!これは大変です(私はストレートなCプログラミングを行ってからしばらくしています)、たくさんのものがハードコードされていて、おそらくstrnc *()関数の長さ計算が乱れていました。同様の例がK & R btwにあります。

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

#include <sys/types.h> 
#include <dirent.h> 

void listdir(char* dirname, int lvl); 

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

    if (argc != 2) { 
    fprintf(stderr, "Incorrect usage!\n"); 
    exit(-1); 
    } 
    listdir(argv[1], 0); 


    return 0; 
} 

void listdir(char* dirname, int lvl) 
{ 

    int i; 
    DIR* d_fh; 
    struct dirent* entry; 
    char longest_name[4096]; 

    while((d_fh = opendir(dirname)) == NULL) { 
    fprintf(stderr, "Couldn't open directory: %s\n", dirname); 
    exit(-1); 
    } 

    while((entry=readdir(d_fh)) != NULL) { 

    /* Don't descend up the tree or include the current directory */ 
    if(strncmp(entry->d_name, "..", 2) != 0 && 
     strncmp(entry->d_name, ".", 1) != 0) { 

     /* If it's a directory print it's name and recurse into it */ 
     if (entry->d_type == DT_DIR) { 
     for(i=0; i < 2*lvl; i++) { 
      printf(" "); 
     } 
     printf("%s (d)\n", entry->d_name); 

     /* Prepend the current directory and recurse */ 
     strncpy(longest_name, dirname, 4095); 
     strncat(longest_name, "/", 4095); 
     strncat(longest_name, entry->d_name, 4095); 
     listdir(longest_name, lvl+1); 
     } 
     else { 

     /* Print some leading space depending on the directory level */ 
     for(i=0; i < 2*lvl; i++) { 
      printf(" "); 
     } 
     printf("%s\n", entry->d_name); 
     } 
    } 
    } 

    closedir(d_fh); 

    return; 
} 
+0

strncmp(name、 "。"、1)はドットファイルを除外します。また、切り捨てられた名前の下で処理を試みるよりも、(警告付きで)スキップする方がよいでしょう。最後に、ループの代わりに、インデントを印刷するためのこのかわいいトリックがあります:static char spaces [] = ""; printf( "%s"、spaces [max(0、strlen(spaces) - count)]); – ephemient