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 再帰呼び出しでフォルダを潜る >
『につづく!』
「動的配列に再帰呼び出し、要復習!」
『うぉ、総力戦ですか!?』