こんにちは!マクロの記録を卒業し、「いよいよ本格的なVBAの自動化に挑戦したい!」というステップに進まれたあなたへ。
今回は、業務自動化エンジニアとして現場で最もよく使う、そしてVBAのレベルアップに不可欠な「再帰呼び出し(さいきよびだし)」をテーマにお話しします。
「指定したフォルダの中にあるファイルをすべて処理したい。しかも、その中のサブフォルダ、さらにその下のフォルダまで全部くまなく……!」
こんな要望、実務ではよくありますよね。これを普通のループだけで書こうとすると、フォルダの階層が深くなるにつれてコードが複雑怪奇になり、破綻してしまいます。
そこで登場するのが、FileSystemObject(FSO)と「再帰処理」のコンビネーションです。
ここをクリアすれば、あなたのVBAスキルは確実に一段上のステージに上がります。優しく、そして本質的なところまで丁寧に解説していきますので、ぜひ最後までついてきてくださいね!
—
1. なぜ「再帰呼び出し」が必要なのか?
まず、私たちが直面する問題の正体を知りましょう。
例えば、次のようなフォルダ構造があったとします。
📁 2023年度売上データ(親フォルダ)
┣ 📄 全体サマリー.xlsx
┣ 📁 1Q(サブフォルダ)
┃ ┣ 📄 4月.xlsx
┃ ┗ 📄 5月.xlsx
┗ 📁 2Q(サブフォルダ)
┣ 📁 7月詳細(孫フォルダ)
┗ 📄 8月.xlsx
「一番上の親フォルダの中にあるファイルをすべて処理する」だけであれば、`Dir`関数や単純なループで事足ります。しかし、「何階層下にあるかわからないサブフォルダの中身まで、もれなく全部回収したい」となった途端、話が変わります。
「ロシアの人形(マトリョーシカ)」をイメージしよう
ここで「再帰呼び出し」の出番です。
再帰とは一言で言えば、「自分自身の中に、自分自身をもう一度呼び出す仕組み」のことです。
マトリョーシカを開けたら、また一回り小さな人形が出てくる……あれと同じです。
1. フォルダを開く
2. 中にあるファイルを処理する
3. もし「サブフォルダ」を見つけたら、そのフォルダに対して「全く同じ処理(1〜3)」をもう一度行う
この「自分をもう一度呼ぶ」という発想が腑に落ちると、どんなに複雑に入り組んだフォルダ階層であたふたする必要がなくなります。
—
2. 実装の武器:FileSystemObject(FSO)
VBAでファイルやフォルダを操作するとき、古い`Dir`関数や`MkDir`ステートメントを使うのは、現代の開発においては少し非効率でエラーに弱いです。
そこで、強力なオブジェクト群である `Scripting.FileSystemObject`(通称:FSO) を使います。
これを使うには、VBE(VBAエディタ)のメニューから「ツール」>「参照設定」で「Microsoft Scripting Runtime」にチェックを入れる方法(早期バインディング)もありますが、今回はコードをコピペするだけで動くように、実行時に生成する遅延バインディング(CreateObject)の形式で記述します。
—
3. 【実用コード】全フォルダ・全ファイル探索マクロ
それでは、実際に動くコードを見てみましょう。
エクセルを開き、標準モジュールに以下のコードを貼り付けてみてください。デスクトップにある任意のフォルダパスを指定して実行すれば、中にあるすべてのファイル名をイミディエイトウインドウに出力してくれます。
‘ =====================================================================
‘ テーマ: フォルダ階層を再帰的に巡回し、全ファイルを取得するプロシージャ
‘ =====================================================================
Sub RunFileSearch()
Dim targetPath As String
‘ 【重要】探索したい親フォルダのパスをここに指定してください(最後は必ず「\」で終わる)
targetPath = “C:\Users\YourUserName\Desktop\テストフォルダ\”
‘ フォルダが存在するかチェック
Dim fso As Object
Set fso = CreateObject(“Scripting.FileSystemObject”)
If Not fso.FolderExists(targetPath) Then
MsgBox “指定されたフォルダが存在しません:” & vbCrLf & targetPath, vbCritical
Exit Sub
End If
Debug.Print “=== ファイル探索を開始します ===”
‘ 再帰処理を行うメインのサブルーチンを呼び出す
Call TraverseFolders(fso.GetFolder(targetPath))
Debug.Print “=== すべての探索が完了しました ===”
‘ メモリ解放
Set fso = Nothing
End Sub
‘ =====================================================================
‘ サブルーチン: 再帰的にフォルダを探索する本体
‘ 引数: 処理対象のFolderオブジェクト
‘ =====================================================================
Private Sub TraverseFolders(ByVal currentFolder As Object)
Dim subFolder As Object
Dim fileItem As Object
‘ —————————————————————–
‘ 1. 現在のフォルダにある「ファイル」に対する処理
‘ —————————————————————–
For Each fileItem In currentFolder.Files
‘ ここに「ファイルに対する実務処理」を記述します
‘ 例として、イミディエイトウインドウにフルパスを出力
Debug.Print “ファイル発見: ” & fileItem.Path
‘ ※もしエクセルファイルだけを処理したいなら、拡張子をチェックする
‘ If LCase(fso.GetExtensionName(fileItem.Name)) = “xlsx” Then …
Next fileItem
‘ —————————————————————–
‘ 2. 現在のフォルダにある「サブフォルダ」に対する再帰処理
‘ —————————————————————–
For Each subFolder In currentFolder.SubFolders
‘ ★ここが再帰の心臓部!
‘ 自分自身(TraverseFolders)をもう一度呼び出し、
‘ 次は「そのサブフォルダ」を中身の主役に設定する
Call TraverseFolders(subFolder)
Next subFolder
End Sub
コードのここがポイント!
- `currentFolder.Files` のループ: 今いる階層にあるファイルをすべて舐め尽くします。
- `currentFolder.SubFolders` のループ: 今いる階層にある「別のフォルダ」を見つけるたびに、「おーい、今の処理をそのフォルダでもう一回やってくれ!」と自分自身(`TraverseFolders`)を呼び出し直します。 これにより、無限に深い階層であっても自動で潜っていけるのです。
—
4. 初学者が陥りやすい「3大トラップ」と対策
再帰呼び出しやファイル操作を扱うとき、初学者が必ずと言っていいほどハマる罠があります。プログラミングの現場で泥をなめてきた先輩から、あらかじめ回避策を授けておきますね。
トラップ①:無限ループやスタックオーバーフロー(恐ろしいエラー)
- 原因: フォルダ構造に「シンボリックリンク」や「ショートカットのループ」などが含まれていて、無限に自分を呼び出し続けてしまうと、VBAのメモリ限界を超え、「プロシージャの呼び出しが多すぎます(Error 28)」という恐ろしいエラー(スタックオーバーフロー)で強制終了します。
- 対策: 基本的なWindowsの階層構造(FSOの`SubFolders`)であれば滅多に起きませんが、アクセス権限がないフォルダ(例: `System Volume Information` など)に突撃してエラーになることがあります。必要に応じて `On Error Resume Next` でガードするなどの配慮を入れましょう。
トラップ②:パスの文字数制限(MAX_PATH問題)
- 原因: Windowsの仕様上、ファイルパスの総文字数が260文字を超えると、FSOがファイルを認識できずにエラーを吐くことがあります。
- 対策: 階層があまりに深すぎるフォルダ構成を自動化の対象にする場合は、親フォルダをなるべく浅い場所(`C:\Work\` など)に置いてから実行する運用ルールを作りましょう。
トラップ③:処理の途中で「ファイルを開けない」エラー
- 原因: 探索したエクセルファイルをコード内で開く処理(`Workbooks.Open`)を入れた際、すでに誰かが開いていて「読み取り専用」ダイアログが出たり、アクセス権限がなくて弾かれたりするケースです。
- 対策: ファイルを操作する前には必ず「拡張子のチェック」や「エラーハンドリング(`On Error GoTo`)」を挟み、1つのファイルのせいで全体の自動化がストップしない堅牢な設計(ロバスト性)を意識しましょう。
—
まとめ:ここをクリアすれば、あなたはもう初心者ではない!
今回は、FSOと再帰処理を組み合わせたフォルダ階層の全探索について解説しました。
- フォルダの中にフォルダがあるときは「再帰呼び出し(自分をもう一度呼ぶ)」を使う。
- ファイル操作には `Dir` よりも強力でモダンな `FileSystemObject` を使う。
この2つの武器を手に入れたあなたは、もう「マクロの記録をちょこっと直すだけの初心者」ではありません。複雑な業務プロセスをシステム的に解決できる「自動化エンジニア」の扉を確実に開いています。
現場で実際にこのコードをベースにして、ファイルを一括で集計したり、リネームしたりするツールを作ってみてください。「おっ、動いた!」という感動が、あなたのVBAスキルをさらに加速させてくれるはずです。
それでは、次回の実用テクニック解説もお楽しみに!快適なVBAライフを!
