全サブディレクトリ探索

 プログラムの中で、あるディスクやディレクトリのサブディレクトリのリストが欲しくなる事があります。今回は、指定したディレクトリ内のファイル・ディレクトリを探す探索関数FindFirst、FindNextでサブディレクトリを取得してみましょう。サブディレクトリには、通常サブディレクトリ内のサブディレクトリ(要するに指定したディレクトリ以下の全階層のディレクトリ)が含まれるため、再帰的な処理が必要になります。

 FindFirst,FindNextが返すWIN32_FIND_DATA構造体には、ファイルの属性を示すdwFileAttributesメンバがあり、ここのFILE_ATTRIBUTE_DIRECTORYビットを調べる事で見つかったファイルがディレクトリかどうか検査できます。例えば、FindFirstCドライブの全ファイルを指定して見つかったファイルがディレクトリか検査するなら以下のようになるわけです。

  WIN32_FIND_DATA fFind;
  HANDLE hSearch;

  hSearch=FindFirstFile("c:\\*.*",&fFind); /* 探索開始 */

  if ((fFind.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)!=0)

 サブディレクトリとはディレクトリ内のディレクトリですから、サブディレクトリの取得はこのようにして見つかったディレクトリのリストを作る処理になります。後は、見つかったディレクトリ内のサブディレクトリも順次探して行けば、指定したディレクトリの全サブディレクトリを探した事になるはずですね。サブディレクトリ内のサブディレクトリを探すには、見つかったサブディレクトリを引数に探索関数を再帰呼び出しすれば良いでしょう。
 なお、FindFirst,FindNextは結果として親ディレクトリ(..)と自分自身(.)まで返すので、実際のサブディレクトリの判定は以下のようにしなければなりません。この判定をしないと、再帰呼び出しで自分自身や親のディレクトリを探そうとするために無限再帰に陥ります。

  if ((fFind.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)!=0 && 
    lstrcmp(fFind.cFileName,".")!=0 &&
    lstrcmp(fFind.cFileName,"..")!=0){ /* サブディレクトリの処理 */

 以上の事からサブディレクトリの探索関数は、指定したディレクトリ内のサブディレクトリを探しさらにそのディレクトリを引数に自分自身を再帰呼び出しする関数になります。再帰の終了条件は、サブディレクトリが見つからなくなる事、ですね。

  void searchDir(char *lpszDir,HWND hwLst) { /* サブディレクトリ探索 */

      WIN32_FIND_DATA fFind;
      char lpszPath[MAX_PATH];
      char lpszSDir[MAX_PATH];
      HANDLE hSearch;

      if (lpszDir[strlen(lpszDir)-1]!='\\') /* 最後が"\" か? */
            lstrcat(lpszDir,"\\"); /* 検索するファイル名作成 */

      lstrcpy(lpszPath,lpszDir); /* 探索パスを作成 */
      lstrcat(lpszPath,"*.*");

      hSearch=FindFirstFile(lpszPath,&fFind); /* 探索開始 */

      if (hSearch==INVALID_HANDLE_VALUE) { /* 見つからなければ探索終了 */

          FindClose(hSearch);
          return;

      }

      if ((fFind.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)!=0 && 
        lstrcmp(fFind.cFileName,".")!=0 &&
        lstrcmp(fFind.cFileName,"..")!=0){ /* サブディレクトリの処理 */

          lstrcpy(lpszSDir,lpszDir); /* サブディレクトリのパス作成 */
          lstrcat(lpszSDir,fFind.cFileName);
          SendMessage(hwLst,LB_ADDSTRING,0,(LPARAM)lpszSDir); /* 表示 */

          searchDir(lpszSDir,hwLst); /* 再帰呼び出し */

      }

      while (FindNextFile(hSearch,&fFind)) { /* 全ファイルを処理 */

          if ((fFind.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)!=0 && 
            lstrcmp(fFind.cFileName,".")!=0 &&
            lstrcmp(fFind.cFileName,"..")!=0) {

              lstrcpy(lpszSDir,lpszDir);
              lstrcat(lpszSDir,fFind.cFileName);
              SendMessage(hwLst,LB_ADDSTRING,0,(LPARAM)lpszSDir);

              searchDir(lpszSDir,hwLst);

          }

      }

      FindClose(hSearch);

  }

 この関数では、見つかったサブディレクトリのパス(lpszSDir)をリストボックス(hwList)に表示してからそのパスを引数に再帰呼び出ししています。この関数を呼び出すと、引数に指定したディレクトリ内の全サブディレクトリをリストに表示するわけです。

プログラム

 開始ボタンをクリックすると、Cドライブのサブディレクトリを探します。ただし、探すディレクトリ数は最大256個に制限しました。結果を見ると、サブディレクトリ内のディレクトリを次々に辿って行くのがわかりますね。

 なお、98シリーズなどでCドライブがない場合や他のディレクトリを探したい時は、searchDir()の引数を変更してください(ウインドウプロシージャ−のWM_COMMANDで呼び出しています)。

プログラムソース表示


Windowsプログラミング実験室 > プログラミング資料庫