FindFirstFileでのサブディレクトリ内全てを検索するには?

解決


DD.  2005-09-14 21:06:49  No: 58972

お世話になっております。DD.でございます。

少々長くなってしまいました。申し訳ございません。

只今、FindFirstFileを使用して、指定フォルダ以下の
サブフォルダを含めたファイルの検索を行っております。

FindFirstFileの第1引数に"フォルダ名+*(c:\*)"のように指定すると
第2引数である WIN32_FIND_DATA 構造体の cFileName メンバに
検索フォルダ内にある、条件に一致される最初のフォルダ及びファイルが
検索されます。

ただ、第1引数を"フォルダ名(c:\)"とした場合、第2引数である WIN32_FIND_DATA 構造体の cFileName メンバに
カレントディレクトリ(=プロジェクト名)が入ってしまいます。

#カレントディレクトリ(=プロジェクト名)とさせて頂いたのは
#カレントディレクトリとプロジェクト名が同じなので
#どちらから取られているのかわからないためです。

カレントディレクトリへのパスが入るならばまだしも
カレントディレクトリ名が入ってしまうので、
「カレントディレクトリ = c:\aaa\bbb\カレント」
であったとしても FindFirstFile 的には
「c:\カレント」に、なってしまい、当然フォルダ及びファイルは見つからないとなってしまいます。

MSDNより、第1引数に
「"有効なディレクトリ名"、またはパス名とファイル名を保持している、NULL で終わる文字列へのポインタを指定します。」

とあるので、ファイルパスではなく、フォルダパスを引数に与えただけなのですが、これではいけないのでしょうか?

以下、その部分のソースを抜粋致します。

//sFindPath = 指定ファイル名, sFindDir = 指定フォルダ, sFindFile = "*"
sprintf( sFindPath, "%s\\%s", sFindDir, sFindFile );  
WIN32_FIND_DATAA find_file;  

// ここでWIN32_FIND_DATA::cFileName = カレントディレクトリになります
HANDLE hFind = FindFirstFileA( sFindDir, &find_file );
if ( hFind != INVALID_HANDLE_VALUE ) {
  do {
    if ( strcmp( find_file.cFileName, "." ) &&
         strcmp( find_file.cFileName, ".." ) ) {
      if ( find_file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
        // フォルダ時
        char sFindSubDir[_MAX_PATH];
        sprintf( sFindSubDir, "%s\\%s", FindDir,find_file.cFileName );
        // サブディレクトリ内検索
        // filelist関数は"この"関数です。再帰になっています。
        file_cnt += filelist( sFindSubDir, sFindFile );
      } else {
        // ファイル時
        // ここで検索ファイルと一致するかどうかを調べてる...つもり
        if ( FindFirstFileA( sFindPath, &find_file ) 
                                           !=INVALID_HANDLE_VALUE ) {
          sprintf( sGetFilePath, "%s\\%s", sFindDir,
                                               find_file.cFileName );
          // vector に検索されたファイル名を格納しています
          vs.push_back( sGetFilePath );      
          ++file_cnt;
        }
      }
    }
  } while ( FindNextFileA( hFind, &find_file ) );
  FindClose( hFind );
}

以上のソースで FindFirstFile の仕様及び認識の間違いによるご指摘、
プログラム的なつっこみも感激です。

よろしくお願い致します。


KING・王  2005-09-14 21:51:04  No: 58973

はずしていたらごめんなさい。

MSDNより
> FindFirstFile の lpFileName パラメータでは、最後に円記号(\)を付けるかどうかにかかわりなく、ルートディレクトリを指定することはできません。

とありますが、大丈夫ですか?

また、さらにMSDNより
>ルートディレクトリ以外のディレクトリを検索するには、そのディレクトリを指す適切なパス名を指定し、最後の円記号(\)を付けないでください。たとえば、"C:\windows" という文字列を指定すると、そのディレクトリ内のファイルやサブディレクトリに関する情報ではなく、そのディレクトリに関する情報を取得できます。最後の円記号をつけて検索を行おうとすると、必ずこの関数は失敗します。

とありますが、これは関係ありませんか?

#あまり詳しく見ていないので、外しているようならごめんなさい。

それから、MSDNのWIN32_FIND_DATAの説明に、
> cFileName 
>   A null-terminated string that is the name of the file. 
とあるので、パス名ではなくファイル名(フォルダ名)なのは当然では?


DD.  2005-09-14 22:32:42  No: 58974

KING・王さん回答ありがとうございます。

> FindFirstFile の lpFileName パラメータでは、最後に円記号(\)を付け
>るかどうかにかかわりなく、ルートディレクトリを指定することはできませ
>ん。
一応 C:\ の Windows フォルダや、その他フォルダも試したのですが、
もし、C:\Windows を指定した場合、cFileName には、なぜか"Windows"が
入ってしまい、パスを sprintf で連結する際に、C:\Windows\Windows 
になって、検索されてしまいます。orz

>最後の円記号をつけて検索を行おうとすると、必ずこの関数は失敗します。
これも実験済みで、'\'を付けてしまうと、そもそも FindFirstFile で
エラーになってしまいました。

>A null-terminated string that is the name of the file. 
>とあるので、パス名ではなくファイル名(フォルダ名)なのは当然では?
あ・・・まさしく^^;
はずかしながら英語は読めないのですが、単語単語をたどっていけば
十分理解できる内容ですね。
つい、英語はスルーしてしまう悪い癖が;;
治さないといけませんね。

これは原因かもしれませんね。
でも、それにしても WIN32_FIND_DATA に変なパスが入ってしまうのが
謎です。。。

自分の調査不足な部分をご指摘頂きありがとうございます。
勉強になりました。


DD.  2005-09-14 23:02:57  No: 58975

一応報告です。

> FindFirstFile の lpFileName パラメータでは、最後に円記号(\)を付け
>るかどうかにかかわりなく、ルートディレクトリを指定することはできませ
>ん。
なのですが、上記に記したソースで(一部異なりますが)
FindFirstFile を使ってルートディレクトリ(C: or D: 等)で、
検索を試みましたがうまくファイル検索できました。

どうなんでしょぅ。。。^^;


DD.  2005-09-14 23:53:02  No: 58976

FindFirstFile の扱い方が間違っていたことで
予期せぬ動作を起こしていたと認識しまして、
これでとりあえず解決とさせて頂きます。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加