#pragma twice

KAB-studio > プログラミング > #pragma twice > 294 Version 14.27 フォルダを潜るファイル検索

#pragma twice 294 Version 14.27 フォルダを潜るファイル検索

前のページへ 表紙・目次へ 次のページへ

 Version 14.27
フォルダを潜るファイル検索

今回は、前回中途半端に作ったファイル検索機能をもう少しちゃんとして
みます
おー
というわけで、まずは完成品のコードから

/*
    指定したフォルダからファイルを検索します。
    戻り値として一致数を返します。
 */
int CountMatchFile
    ( const char * const p_pchFolderPath
    , const char * const p_pchFileName 
    )
{
    int iNum = 0;

    // 検索するフォルダをカレントディレクトリにします。
    BOOL bRes;
    bRes = SetCurrentDirectory( p_pchFolderPath );
    if( bRes == FALSE )
    {
        // フォルダが存在しません。
        return -1;
    }

    CStringArray cFolderStrAry;

    // 最初のファイルを取得します。
    WIN32_FIND_DATA stWin32FindData;
    HANDLE hHandle = NULL;
    hHandle = FindFirstFile( "*", &stWin32FindData );
    do
    {
        if( stWin32FindData.dwFileAttributes 
                & FILE_ATTRIBUTE_DIRECTORY )
        {
            // フォルダなので取っておきます。
            cFolderStrAry.Add( stWin32FindData.cFileName );
        }
        else if( _stricmp
                ( stWin32FindData.cFileName
                , p_pchFileName 
                ) == 0 )
        {
            // ファイル名が一致しました。
            ++iNum;
        }

        // 次のファイルを取得します。
    }while( FindNextFile( hHandle, &stWin32FindData ) );

    // ハンドルを閉じます。
    FindClose( hHandle );

    // フォルダに対して再帰呼び出しをします。
    for( int iF1 = 0; iF1 < cFolderStrAry.GetSize(); ++iF1 )
    {
        if  (
            ( cFolderStrAry.GetAt( iF1 ) == "." ) ||
            ( cFolderStrAry.GetAt( iF1 ) == ".." )
            )
        {
            // . と .. はスキップします。
            continue;
        }

        // フォルダを連結します。
        CString cPathStr = p_pchFolderPath;
        if  (
            ( cPathStr.GetAt
                ( cPathStr.GetLength() - 1 ) != '\\' ) &&
            ( _mbsbtype
                ( (const unsigned char *)(LPCTSTR)cPathStr
                , cPathStr.GetLength() - 1 
                ) == 0 )
            )
        {
            // 最後に \ がなければくっつけます。
            cPathStr += "\\";
        }
        cPathStr += cFolderStrAry.GetAt( iF1 );
        // 再帰呼び出しします。
        iNum += CountMatchFile( cPathStr, p_pchFileName );
    }

    return iNum;
}

void CSearchDlgDlg::OnSearchStart() 
{
    int iCount = 0;
    iCount = CountMatchFile( "D:\\", "readme.txt" );
    TRACE( "一致数: %d\n", iCount );

    // 【検索中】ダイアログを表示します。
    // CSearchingDlg cDlg;
    // cDlg.DoModal();
}

長!
しかも、今回はかなり複雑だよ
げげ
たまにはこういう本格的なプログラムもね。まずは

    iCount = CountMatchFile( "D:\\", "readme.txt" );

の CountMatchFile() の説明から。この関数は前回と同じく、第1引数に
検索対象のフォルダ、第2引数に検索するファイルを渡すと、戻り値に一致
した件数を返します
前と同じね
ただ違うのは、今回はフォルダを深く潜っていくっていう機能を追加しま
した。つまり、この例だと D:\ の下のフォルダのを全部検索します
おー、なんか本格的
では、実際に関数の中を見てみます

    // 検索するフォルダをカレントディレクトリにします。
    BOOL bRes;
    bRes = SetCurrentDirectory( p_pchFolderPath );
    if( bRes == FALSE )
    {
        // フォルダが存在しません。
        return -1;
    }

フォルダがないときは -1 を返す、ね
ただ、これは使う場合にはちょっとわかりづらいかも
でも、エラー処理ならこれもひとつの方法だよね
うん、 Version 13.05 ( No.241 ) でやったね。まぁこの関数はあとから
もっと手を加えるから、その時に考えてもいいかも。では次

    hHandle = FindFirstFile( "*", &stWin32FindData );

前回と違うのは、前回は "*.*" で検索していたのを、今回は "*" にした
こと
? ほとんど同じじゃない?
 "*.*" でひっかからないものと言えば?
えー? ファイルならまずひっかかる……あ! フォルダ!
そういうこと。今回はフォルダも検索対象にしました
そっか、フォルダを深く深く潜ってくんだもんね
そこで、フォルダかどうか判別してみます

        if( stWin32FindData.dwFileAttributes 
                & FILE_ATTRIBUTE_DIRECTORY )
        {
            // フォルダなので取っておきます。
            cFolderStrAry.Add( stWin32FindData.cFileName );
        }

フォルダの場合、WIN32_FIND_DATA::stWin32FindData.dwFileAttributes 
に FILE_ATTRIBUTE_DIRECTORY フラグが立っています
これを調べて……?
 cFolderStrAry は CStringArray 
 Version 13.12 ( No.248 ) の、文字列を入れられるのだね
この中に、見つかったフォルダをどんどん入れていきます
ん? 取っておくの?
そう、あとでそのフォルダを見に行くから。たとえば、 folder_root と
いうフォルダの中が以下のような構成になっているとします

folder_root
    folderA
        fileX
    folderB
        fileY
    fileA
    fileB
    fileC

この folder_root を検索する場合、次の二通りの検索方法があります

1.folderA や folderB の中を先に検索する。
 fileA とかを探すのは後回し。
2.まず folder_root の中を全部見る。
 それから folderA や folderB の中を見る。

あたしが言ったのが 1 の方で、水希ちゃんが作ったのが 2 の方?
そういうこと。この方法の違いは、【最後まで検索する】場合にはほとん
ど違いがないんだけど、【途中でキャンセルする】場合には大きく異なりま

普通にファイル検索するときって 2 の方だよね、そうじゃないと、 
fileB を見つけるのに時間掛かりそう……
でも検索内容によっては 1 の方がいい場合もあるから
用途によって変える、ってこと?
そういうこと。というわけで次回に続く!
ええっ!?

/*
    Preview Next Story!
*/
まだ半分以上残ってる……
その半分が重要なんです
重要?
久々にプログラムのテクニックについての説明、かな
久々っていうのもどうかねー
というわけで次回
< Version 14.28 再帰呼び出しでフォルダを潜る >
につづく!
動的配列に再帰呼び出し、要復習!
うぉ、総力戦ですか!?
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。