前回はDir関数を利用したファイル検索を検証した。
今回は再帰処理を利用して指定フォルダ内だけでなく、フォルダ内のフォルダの中身を検索できるようにしてみる。
再帰処理でフォルダ内検索
前回は1つのプロシージャで実現したが、今回は3つのプロシージャに分割して機能を実現した。
・FileSearch・・・前処理や検索結果のセルへの転記を行う
・DirSearch関数・・・前処理やCollectionに蓄積した検索結果を配列へ変換する
・Dir_Search・・・DirSearch内で呼び出される。実際のDir関数での検索を行う。
FileSearch
Option Explicit Dim myCol As Collection '----------------------------------------------------------------------------------- Sub FileSearch() Cells.Clear Set myCol = New Collection Dim myVar As Variant myVar = DirSearch("C:\Users\ユーザー名\Desktop\", True) 'DirSearchの返り値が空配列でなければセルに検索結果を転記 If UBound(myVar) <> -1 Then Range("A1").Resize(UBound(myVar), 1).Value = myVar End If Set myCol = Nothing End Sub
冒頭でモジュールレベル変数でCollection型を宣言。この変数にDir関数の検索結果を蓄積していく。
ここでは次に紹介するDirSearch関数を呼び出して、検索開始フォルダとサブフォルダ内検索の有無を指定している。
DirSearch関数は検索結果に関わらず、返り値として配列を返すようにしている。
DirSearch関数の返り値に対してUbound関数を使用し、返り値が-1(空配列)であれば検索結果が0であるため処理無しとする。
何らかの検索結果がある場合は2次元配列が返ってきているので、セルサイズを合わせて一括で転記している。
DirSearch関数
'----------------------------------------------------------------------------------- Rem DirSearch関数 Rem 第1引数 FolderPath:検索対象とするフォルダパスを指定する Rem 第2引数 SubFolderSearch:フォルダ内のサブフォルダ内を検索対象とするかどうか Rem 返り値 見つかったファイルのフルパス一覧を2次元配列として返す。 Rem 1件もファイルが見つからなかった場合は空配列を返す。 Rem 関数内sub Dir_Searchが溜め込んだ検索結果コレクションを配列へ転記する '----------------------------------------------------------------------------------- Function DirSearch(FolderPath As String, SubFolderSearch As Boolean) As Variant Dir_Search FolderPath, SubFolderSearch Dim myItem As Variant '検索結果を蓄積していたCollectionから配列へ転記してからセルへ一括転記 If myCol.Count = 0 Then DirSearch = Array() Else Dim myVar As Variant Dim i As Long: i = 1 ReDim myVar(1 To myCol.Count, 1 To 1) For Each myItem In myCol myVar(i, 1) = myItem i = i + 1 Next DirSearch = myVar End If End Function
DirSearch関数は次に紹介するDir_Searchがモジュールレベル変数Collectionに蓄積した検索結果を配列へと変換して外部へ返す役割を担っている。
Dir_Search
'------------------------------------------------------------------------------------- Rem Dir_Search Rem 第1引数 FolderPath:検索対象とするフォルダパスを指定する Rem 第2引数 SubFolderSearch:フォルダ内のサブフォルダ内を検索対象とするかどうか Rem Dir関数を利用してファイル・フォルダを検索。検索結果をモジュールレベルCollectionへ蓄積していく。 '------------------------------------------------------------------------------------- Private Sub Dir_Search(FolderPath As String, SubFolderSearch As Boolean) Dim myFileName As String Dim myFolderCol As Collection Set myFolderCol = New Collection 'ファイルとフォルダを検索対象とする myFileName = Dir(FolderPath, VbFileAttribute.vbSystem + VbFileAttribute.vbHidden + VbFileAttribute.vbDirectory) '検索対象が見つからなくなるまでループ処理 Do Until myFileName = "" '見つかったものが該当フォルダ及び親フォルダの場合は処理なし If myFileName = "." Or myFileName = ".." Then '見つかったものがフォルダ内フォルダの場合はフォルダ一覧コレクションに登録 ElseIf GetAttr(FolderPath & myFileName) And vbDirectory Then myFolderCol.Add FolderPath & myFileName '上記2つ以外はファイル一覧コレクションに登録 Else myCol.Add FolderPath & myFileName End If myFileName = Dir Loop ’サブフォルダー内検索処理 '引数SubFolderSearchがTrueの場合は再帰処理で中を検索していく Dim myItem As Variant If SubFolderSearch = True Then For Each myItem In myFolderCol Dir_Search myItem & "\", SubFolderSearch Next End If End Sub
本件の中核となるDir_Search。
実際にDir関数でファイル・フォルダの検索を行い検索結果をモジュールレベル変数Collectionへ蓄積していく。
Dir関数はフォルダ名・ファイル名のみを返すので、Collectionへ追加する際は親フォルダ部分を追加してから行う。
Dir関数の検出結果がフォルダなのかファイルなのかを判定するためにGeAttr関数とビットアンド演算を利用している。
サブフォルダ以内の検索はDir_Search内からDir_Search自身を呼び出す再帰処理で実現している。
まとめ
DirSearch関数の引数設定をもう少し柔軟に受けることが出来るようにすれば、検索対象の絞り込みも設定できるようになるだろうが、作り込みについては次回以降の別のファイル検索についても検証してからにしてみようと思います。