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関数の制限について
・3桁拡張子の指定時の問題 ・256バイトを超えるパス名が扱えない ・UNICODEファイル名が扱えない ・特殊なネットワークドライブでエラー ・Dir関数の制限の最後に


サイト内関連ページ

第79回.ファイル操作Ⅰ(Dir)
・Dir関数 ・Dir関数の使用例 ・Dir関数の実践例 ・Dir関数の制限について ・Dir関数の関連記事
第119回.ファイルシステムオブジェクト(FileSystemObject)
・FileSystemObjectオブジェクトの使用方法 ・FileSystemObjectオブジェクトのプロパティとメソッド ・FileSystemObjectオブジェクトのメソッドの戻り値 ・FileSystemObjectオブジェクトの使用例 ・FileSystemObjectオブジェクトの関連記事と実践例
エクセルでファイル一覧を作成
VBAでサブフォルダ以下も含めて全てのファイル一覧を取得します。最初はサブフォルダは無視して、VBAにある関数とステートメントだけで作成します、その後に、FileSystemObjectで再帰処理をすることで、全てのサブフォルダも取得するようにしていきます。
DIR関数で全サブフォルダの全ファイルを取得
・Dir関数でサブフォルダも含むファイル一覧を取得するVBA ・ファイル一覧を取得するVBAの使用例と解説 ・Dir関数の関連記事




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

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


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

抜けている数値を探せ|エクセル雑感(2022-07-01)
.Net FrameworkのSystem.Collectionsを利用|VBA技術解説(2022-06-29)
迷路ネコが影分身の術を体得したら…|エクセル雑感(2022-06-27)
迷路にネコが挑戦したら、どうなるかな…|エクセル雑感(2022-06-26)
サロゲートペアに対応した自作関数(Len,Left,Mid,Right)|エクセル雑感(2022-06-24)
「マクロの登録」で登録できないプロシージャーは?|エクセル雑感(2022-06-23)
オブジェクトのByRef、ByVal、Variant|エクセル雑感(2022-06-22)
コメントから特定形式の年月を取り出す|エクセル雑感(2022-06-19)
4,9を使わない連番作成|エクセル雑感(2022-06-17)
連番を折り返して出力|エクセル雑感(2022-06-16)


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

1.最終行の取得(End,Rows.Count)|VBA入門
2.RangeとCellsの使い方|VBA入門
3.変数宣言のDimとデータ型|VBA入門
4.繰り返し処理(For Next)|VBA入門
5.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
6.Excelショートカットキー一覧|Excelリファレンス
7.マクロって何?VBAって何?|VBA入門
8.並べ替え(Sort)|VBA入門
9.Range以外の指定方法(Cells,Rows,Columns)|VBA入門
10.エクセルVBAでのシート指定方法|VBA技術解説




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


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



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