【VBAリファレンス】【Excel VBA】サブフォルダまで完全網羅!Dir関数を用いた再帰呼び出しによるファイル一覧取得術

スポンサーリンク

こんにちは。Excel VBAの講師をしております。

日々の業務で、「特定のフォルダ以下にあるすべてのExcelファイルの一覧を取得したい」「階層化されたフォルダ構造の中から、特定の拡張子のファイルだけをリストアップしたい」といった要望を耳にすることは非常に多いです。

Windowsのエクスプローラーで一つずつ確認するのは非効率ですし、かといって手作業でコピー&ペーストを行うのはミスのもとです。そんな時こそ、VBAの出番です。

今回は、VBAにおけるファイル操作の基本である「Dir関数」を使い、さらに一歩進んだテクニックである「再帰呼び出し(Recursive Call)」を組み合わせて、サブフォルダを含めたすべてのファイルをリストアップする方法を解説します。

なぜ「再帰呼び出し」が必要なのか?

まず、Dir関数についておさらいしましょう。Dir関数は、指定したパスにあるファイル名を取得する関数です。しかし、Dir関数単体では「そのフォルダ直下のファイル」しか取得できません。サブフォルダの中身まで見に行くには、もう一段工夫が必要です。

そこで登場するのが「再帰呼び出し」というプログラミングの概念です。これは、関数の中で自分自身を呼び出す手法のことです。

「フォルダAをチェックし、もしサブフォルダBがあれば、フォルダBを処理する関数をもう一度呼び出す」というロジックを組むことで、階層がどれだけ深くても自動的に潜り込み、すべてのファイルを漏れなく取得することが可能になります。

まずは基本のロジックを理解する

サブフォルダを探索するためには、フォルダとファイルの情報を保持する「FileSystemObject(FSO)」を使う方法も有名ですが、今回はあえて「Dir関数」にこだわります。Dir関数は外部ライブラリの参照設定が不要で、環境を選ばずに動作するというメリットがあるからです。

再帰処理を実装する際の基本的な流れは以下の通りです。

1. 指定したパスのファイルを取得する
2. 取得したものが「フォルダ」であれば、そのパスを引数にして自分自身の関数を再実行する
3. 取得したものが「ファイル」であれば、セルに書き出す

実装コード:サブフォルダを含めたファイル一覧取得

それでは、実際に動作するコードを見ていきましょう。標準モジュールに以下のコードを貼り付けてください。

Option Explicit

‘ メイン処理:ここから実行を開始します
Sub GetFileList_Main()
Dim targetPath As String
targetPath = “C:\Users\YourName\Documents\TestFolder” ‘ ここに目的のパスを指定

‘ 書き出し先のシートをクリア
Cells.Clear
Range(“A1”).Value = “ファイルパス”

‘ 再帰処理の開始
Call ListFilesRecursive(targetPath, 2)

MsgBox “ファイル一覧の取得が完了しました!”, vbInformation
End Sub

‘ 再帰的にフォルダを探索する関数
Sub ListFilesRecursive(ByVal folderPath As String, ByRef rowNum As Long)
Dim fileName As String
Dim subFolderPath As String
Dim folderList As Collection
Dim item As Variant

‘ 末尾に\がない場合は付与
If Right(folderPath, 1) <> “\” Then folderPath = folderPath & “\”

‘ 1. ファイルをすべて取得して書き出す
fileName = Dir(folderPath & “*.*”, vbNormal)
Do While fileName <> “”
Cells(rowNum, 1).Value = folderPath & fileName
rowNum = rowNum + 1
fileName = Dir()
Loop

‘ 2. サブフォルダを検索するために、一旦フォルダ名だけを取得する
‘ (Dir関数は再帰呼び出し中に状態がリセットされるため、コレクションに格納する)
Set folderList = New Collection
fileName = Dir(folderPath, vbDirectory)
Do While fileName <> “”
If fileName <> “.” And fileName <> “..” Then
If (GetAttr(folderPath & fileName) And vbDirectory) = vbDirectory Then
folderList.Add folderPath & fileName
End If
End If
fileName = Dir()
Loop

‘ 3. 取得したサブフォルダに対して、自分自身を呼び出す
For Each item In folderList
Call ListFilesRecursive(item, rowNum)
Next item
End Sub

コードの重要ポイントを解説

このコードで最も注意すべき点は、「Dir関数の性質」です。

Dir関数は一度実行されると、その検索状態をメモリ内に保持します。そのため、再帰呼び出しの中で再度Dir関数を呼び出すと、親階層のDir関数の状態が上書きされてしまい、正しく動作しなくなるという問題が発生します。

これを回避するために、上記のコードでは「サブフォルダのリストを一度コレクション(Collection)に格納してから、ループを回して再帰呼び出しを行う」という工夫をしています。これにより、Dir関数の状態を壊すことなく、階層を深く潜っていくことができます。

また、`If fileName <> “.” And fileName <> “..”` という条件式も重要です。Windowsのフォルダ構成には、自分自身を指す「.」と、親フォルダを指す「..」という特殊なディレクトリが存在します。これを除外しないと、無限ループに陥り、Excelがフリーズしてしまいます。

さらに実務で使いやすくするためのカスタマイズ

このコードをベースに、実務では以下のようなカスタマイズを行うと非常に便利です。

1. 拡張子によるフィルタリング

`Dir(folderPath & “*.*”, vbNormal)` の部分を `Dir(folderPath & “*.xlsx”, vbNormal)` に変更すれば、Excelファイルのみを抽出できます。さらに `If InStr(fileName, “.xlsx”) > 0 Then` のように条件分岐を加えれば、より柔軟なフィルタリングが可能です。

2. ファイル情報の追加

パスだけでなく、ファイルの最終更新日時やサイズも取得したい場合は、`FileDateTime` 関数や `FileLen` 関数を組み合わせます。

Cells(rowNum, 2).Value = FileDateTime(folderPath & fileName)
Cells(rowNum, 3).Value = FileLen(folderPath & fileName)

これだけで、いつ作成されたどのくらいのサイズのファイルなのかが一目でわかる管理表が完成します。

3. パスが長すぎる場合の対策

非常に深い階層のフォルダを扱う場合、パスの長さがWindowsの制限(MAX_PATH)を超えることがあります。その場合は、FSO(FileSystemObject)を使用した実装へ切り替えることを検討してください。FSOはよりオブジェクト指向的で、パスの操作に長けています。

まとめ:VBAで自動化の第一歩を

今回紹介した「Dir関数による再帰呼び出し」は、VBAによるファイル操作の登竜門とも言えるテクニックです。

「フォルダを開いて、中身を確認して、リストに書き写す」という単調な作業をプログラムに任せることで、ミスは激減し、あなたはもっとクリエイティブな分析や意思決定に時間を割くことができます。

最初は難しく感じるかもしれませんが、一度この「再帰」のロジックを理解してしまえば、ファイル操作だけでなく、様々な業務効率化に応用が効くようになります。ぜひ、ご自身のPCにある適当なフォルダで試してみてください。

もしエラーが出る場合は、パスの指定が正しいか、権限のないフォルダ(システムフォルダなど)にアクセスしようとしていないかを確認してみてください。

プロフェッショナルなVBAエンジニアへの道は、こうした小さな自動化の積み重ねから始まります。応援しています!

タイトルとURLをコピーしました