VBA練習問題
VBA100本ノック 66本目:全サブフォルダからファイルを探す

VBAを100本の練習問題で鍛えます
最終更新日:2021-01-14

VBA100本ノック 66本目:全サブフォルダからファイルを探す


ブック自身のあるフォルダ以下の全サブフォルダを検索する問題です。


ツイッター連動企画です。
ツイートでの見やすさを考慮して、ブック・シート指定等を適宜省略しています。

VBAテスト用のサンプルデータはご自身でご用意ください。


出題

出題ツイートへのリンク

#VBA100本ノック 66本目
ブック自身のあるフォルダ以下の全サブフォルダを検索し、自身と同一名称(拡張子含めて)のファイルを探してください。
同一名称のファイルが見つかったら、シートに出力してください。
・A列:フルパス
・B列:更新日時
・C列:ファイルサイズ
※シートは任意


フォルダ配下の全サブフォルダが対象です。
サブフォルダの中にあるサブフォルダの中も検索してください。


VBA作成タイム

この下に頂いた回答へのリンクと解説を掲載しています。
途中まででも良いので、できるだけ自分でVBAを書いてみましょう。


他の人の回答および解説を見て、書いたVBAを見直してみましょう。


頂いた回答

解説

全サブフォルダを探すので通常のループでは対応できません。
再帰的(自身を呼び出す)にフォルダを処理することで、フォルダの全階層を探すようにします。
このような処理を行うためには、現在処理している情報が保持されている必要があります。
FileSystemObjectを使って再帰しています。

Sub VBA100_66_01()
  Dim wb As Workbook: Set wb = ThisWorkbook
  Dim ws As Worksheet: Set ws = wb.ActiveSheet
  Dim cFiles As New Collection
  Dim objFSO As New FileSystemObject
  
  Call getDirFile(cFiles, wb, objFSO.GetFolder(wb.Path))
  Call putToSheet(cFiles, ws)
  
  Set objFSO = Nothing
End Sub

Sub getDirFile(ByVal cFiles As Collection, ByVal wb As Workbook, ByVal aFolder As Folder)
  Dim oFile As File
  For Each oFile In aFolder.Files
    If oFile.Name = wb.Name And oFile.Path <> wb.FullName Then
      cFiles.Add Array(oFile.Path, oFile.DateLastModified, oFile.Size)
    End If
  Next
  
  Dim oFolder As Folder
  For Each oFolder In aFolder.SubFolders
    Call getDirFile(cFiles, wb, oFolder)
  Next
End Sub

Sub putToSheet(ByVal cFiles As Collection, ByVal ws As Worksheet)
  Dim v As Variant, i As Long
  ws.Cells.ClearContents
  ws.Range("A1:C1").Value = Array("フルパス", "更新日時", "ファイルサイズ")
  i = 2
  For Each v In cFiles
    ws.Cells(i, 1).Resize(, 3).Value = v
    i = i + 1
  Next
End Sub


ただしFSOは処理が遅いですね。
Shell.ApplicationやDOSコマンドを使う方法もあります。
またDir関数でも現在処理中のフォルダを別途保存しておくことで全サブフォルダを処理するようにすることもできます。
これについては、記事補足にて。


補足

FileSystemObject以外では以下のような方法があります。

・Shell.Application
・DOSコマンド
・Windows API
・Dir関数

順に頂いた回答へのリンクと、用意した解答コードを掲載しておきます。

Shell.Applicationを使った方法は以下に回答いただきました。
DOSコマンドを使った方法は以下に回答いただきました。
Windows APIを使った方法は以下に回答いただきました。
Dir関数を使ったVBAを作成しました。ただし、特にお勧めはしません。
Sub VBA100_66_02()
  Dim wb As Workbook: Set wb = ThisWorkbook
  Dim ws As Worksheet: Set ws = wb.ActiveSheet
  Dim cFolders As New Collection
  Dim sPath As String, i As Long
  
  ws.Cells.ClearContents
  ws.Range("A1:C1").Value = Array("フルパス", "更新日時", "ファイルサイズ")
  i = 2
  cFolders.Add wb.Path & "\"
  
  Do While cFolders.Count > 0
    sPath = cFolders(1) & wb.Name
    If Dir(sPath) <> "" And sPath <> wb.FullName Then
      ws.Cells(i, 1).Resize(, 3).Value = Array(cFolders(1) & wb.Name, _
                           FileDateTime(sPath), _
                           FileLen(sPath))
      i = i + 1
    End If
    
    sPath = Dir(cFolders(1), vbDirectory)
    Do While sPath <> ""
      If GetAttr(cFolders(1) & sPath) And vbDirectory Then
        If sPath <> "." And sPath <> ".." Then
          cFolders.Add cFolders(1) & sPath & "\"
        End If
      End If
      sPath = Dir()
    Loop
    
    cFolders.Remove 1
  Loop
End Sub

取得したフォルダは順次Collectionに追加していきます。
Collectionを上から処理しつつ、処理したら削除します。
Collectionが無くなった時点で全フォルダが処理されたことになります。

これはDir関数のサンプルというより、Collectionの使い方の参考にしてもらえればと思います。
そして、もちろんDir関数である必要はなく、FileSystemObjectで再帰させずに処理する場合にも使えます。
またCollectionである必要もなく、配列でも何でも良くて、処理するフォルダをキューに入れて順次なくなるまで処理して行けば同じことができます。

Dir関数は制限が多いので、幅広いフォルダを検索する時はお勧めしません。
Dir関数の制限について
Dir関数は、VBAでフォルダ・ファイルの存在確認や一覧取得において使われる関数ですが、いくつかの使用上の注意点、制限事項があります。3桁拡張子の指定時の問題 このように指定した場合、xlsxやxlsmも対象となります。3桁の拡張子を指定した場合は、4桁の拡張子も対象となります。


サイト内関連ページ

第79回.ファイル操作Ⅰ(Dir)
VBAでは、フォルダのファイル一覧を取得したりファイルの存在確認をする事が出来ます、Dir関数は、指定したパターン(ワイルドカード)やファイル属性と一致するファイルまたはフォルダの名前を表す文字列の値を返します。引数に指定したファイルが存在すると、そのファイル名を返し存在しないと空欄を返します。
第119回.ファイルシステムオブジェクト(FileSystemObject)
FileSystemObjectオブジェクトでは、コンピュータのファイルシステムへのアクセスが提供されています。VBAに用意されているファイル操作関連のステートメントや関数より、より強力で、より多くの機能が搭載されています。ただし機能が大変多いため、これらを全て覚えるという事は困難です。
エクセルでファイル一覧を作成
VBAでサブフォルダ以下も含めて全てのファイル一覧を取得します。最初はサブフォルダは無視して、VBAにある関数とステートメントだけで作成します、その後に、FileSystemObjectで再帰処理をすることで、全てのサブフォルダも取得するようにしていきます。
DIR関数で全サブフォルダの全ファイルを取得
指定フォルダ以下の全サブフォルダ内の全ファイルを取得する場合、通常はFileSystemObjectの再帰モジュールで実現しますが、これをDir関数だけで、かつ、再帰ではなく二重ループで実現しています。FileSystemObjectの再帰プロシージャーについては、エクセルでファイル一覧を作成 こちらをご覧ください。




同じテーマ「VBA100本ノック」の記事

63本目:複数シートの連結
64本目:リンクされた図(カメラ機能)
65本目:固定長テキスト出力
66本目:全サブフォルダからファイルを探す
67本目:ComboBoxとListBox
68本目:全テキストボックスの転記
69本目:ダブルクリックでセル結合を解除
70本目:ステータスバーに1秒ごとに時刻が表示
71本目:パワーポイントへグラフを貼り付け
72本目:ITをDXに変換(文字列操作)
73本目:新規ブックにボタン作成しマクロ登録


新着記事NEW ・・・新着記事一覧を見る

日付型と通貨型のValueとValue2について|エクセル雑感(2021-06-26)
DXってなんだ? ITと何が違うの?|エクセル雑感(2021-06-24)
エクセルVBA 段級位 目安|エクセル雑感(2021-06-21)
ローカル版エクセルが「Office Scripts」に変わる日|エクセル雑感(2021-06-10)
新関数SORTBYをVBAで利用するラップ関数を作成|VBA技術解説(2021-06-12)
VBA今日のひとこと on Twitter|エクセル雑感(2021-06-10)
VBAの演算子まとめ(演算子の優先順位)|VBA技術解説(2021-06-09)
画像が行列削除についてこない場合の対処|VBA技術解説(2021-06-04)
エクセル関連で「いいね」の多かったツイート|エクセル雑感(2021-05-17)
キーボード操作だけで非表示列を表示|エクセル雑感(2021-05-11)


アクセスランキング ・・・ ランキング一覧を見る

1.最終行の取得(End,Rows.Count)|VBA入門
2.Excelショートカットキー一覧|Excelリファレンス
3.変数宣言のDimとデータ型|VBA入門
4.RangeとCellsの使い方|VBA入門
5.マクロって何?VBAって何?|VBA入門
6.繰り返し処理(For Next)|VBA入門
7.Range以外の指定方法(Cells,Rows,Columns)|VBA入門
8.セルに文字を入れるとは(Range,Value)|VBA入門
9.とにかく書いてみよう(Sub,End Sub)|VBA入門
10.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門




このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。


記述には細心の注意をしたつもりですが、
間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。
掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。



このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
本文下部へ