概要
Excel VBAを用いた業務自動化において、最も頻繁に発生する処理の一つが「ファイルの保存」です。しかし、単に名前を付けて保存するだけでは、実務上の要件を満たせないことが多々あります。特に、「年月単位」や「案件単位」でフォルダを自動生成し、存在しない階層であれば新規作成した上で保存するというプロセスは、手作業で行うとミスを誘発しやすく、自動化による恩恵が極めて大きい領域です。本記事では、複数階層のフォルダを自動作成し、安全かつ確実にブックを保存するためのテクニックを、エラーハンドリングを含めて徹底的に解説します。
詳細解説:階層フォルダ作成のロジック
VBAでフォルダを作成する際、標準的な「MkDir」関数は、指定されたパスの「親フォルダ」が存在しない場合、エラー(実行時エラー76:パスが見つかりません)を返します。つまり、C:\Reports\2023\10月 というパスを作りたいとき、C:\Reports すら存在しない状態では MkDir では一度に作成できないのです。
これを解決するためのアルゴリズムには、大きく分けて二つのアプローチがあります。
1. パスを「\」で分解し、親から順に一つずつ存在確認を行いながら作成していく手法。
2. Windows Script Host (WSH) を利用し、ファイルシステムオブジェクト (FileSystemObject: FSO) を活用する手法。
現代的なVBA開発において推奨されるのは、圧倒的に後者の「FSOを利用する手法」です。FSOはフォルダの存在チェック(FolderExists)や作成(CreateFolder)が直感的であり、かつエラーの制御も容易だからです。また、再帰処理を組み合わせることで、どれほど深い階層であっても、一行の命令でフォルダ構成を構築することが可能になります。
サンプルコード:安全かつ確実に保存する実装
以下のコードは、指定したパスが存在しなければ自動的に作成し、その後にブックを保存する汎用的なプロシージャです。
Option Explicit
' フォルダ作成と保存を行うメインプロシージャ
Sub SaveWorkbookWithFolderAutoCreate()
Dim targetPath As String
Dim folderPath As String
Dim fileName As String
' 保存先の親フォルダとファイル名を設定
folderPath = ThisWorkbook.Path & "\Reports\" & Format(Date, "yyyy\mm")
fileName = "Report_" & Format(Date, "yyyymmdd") & ".xlsx"
targetPath = folderPath & "\" & fileName
' フォルダ階層の作成
If CreateFolders(folderPath) Then
' 保存処理(既存ファイルがあっても上書きする設定)
On Error Resume Next
Application.DisplayAlerts = False
ThisWorkbook.SaveAs Filename:=targetPath, FileFormat:=xlOpenXMLWorkbook
Application.DisplayAlerts = True
If Err.Number = 0 Then
MsgBox "保存が完了しました:" & vbCrLf & targetPath, vbInformation
Else
MsgBox "保存中にエラーが発生しました:" & Err.Description, vbCritical
End If
On Error GoTo 0
Else
MsgBox "フォルダの作成に失敗しました。", vbCritical
End If
End Sub
' 複数階層フォルダを再帰的に作成する関数
Function CreateFolders(ByVal path As String) As Boolean
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
On Error Resume Next
' 親フォルダが存在しない場合は再帰的に作成
If Not fso.FolderExists(fso.GetParentFolderName(path)) Then
If Not CreateFolders(fso.GetParentFolderName(path)) Then
CreateFolders = False
Exit Function
End If
End If
' ターゲットフォルダを作成
If Not fso.FolderExists(path) Then
fso.CreateFolder path
End If
CreateFolders = True
On Error GoTo 0
End Function
このコードのポイントは、`CreateFolders` 関数が自分自身を呼び出す「再帰構造」になっている点です。これにより、C:\A\B\C という深い階層であっても、C がなければ B を探し、B がなければ A を探すという処理が自動的に行われます。
実務アドバイス
実務でVBAを運用する際、単にコードが動くだけでは不十分です。以下の3点を必ず意識してください。
1. パス区切り文字の正規化:
フォルダパスの末尾に「\」が含まれているかいないかで処理が変わることがあります。パスを結合する際は、必ず自前で「\」を付与するか、`fso.BuildPath` メソッドを使用してOSに依存しないパス結合を行うのがプロの作法です。
2. ネットワークドライブへの対応:
共有サーバーやクラウドストレージ(OneDrive/SharePointなど)を保存先に指定する場合、ネットワークの遅延によりフォルダの作成が反映されるまで一瞬のタイムラグが発生することがあります。必要に応じて `DoEvents` を挟むか、作成後にフォルダが存在するか再度確認するステップを入れると堅牢性が向上します。
3. 保存形式の明示:
`SaveAs` メソッドを実行する際、`FileFormat` を省略すると、現在開いているブックの形式を引き継ぎます。しかし、マクロが含まれるブックをマクロなし形式で保存しようとするとエラーになります。保存するブックの要件に合わせて、`xlOpenXMLWorkbook`(xlsx)や `xlOpenXMLWorkbookMacroEnabled`(xlsm)を必ず明示してください。
4. ユーザーへのフィードバック:
保存処理は一瞬で終わらない場合もあります。処理中は `Application.StatusBar` に「保存中…」と表示させるなど、ユーザーがフリーズと勘違いしないような配慮が、使いやすいツールの分かれ道となります。
まとめ
複数階層のフォルダを自動作成してファイルを保存する技術は、Excel VBAによるシステム開発における「基本にして奥義」と言えます。MkDirによる原始的な方法から卒業し、FileSystemObjectを活用した再帰的なフォルダ作成手法を身につけることで、あなたの作成するマクロの信頼性は飛躍的に向上します。
今回紹介したコードは、そのままモジュールにコピー&ペーストして利用可能です。パスの指定部分を動的に変更するようにアレンジすれば、どんな複雑なフォルダ構造にも対応できる強力なライブラリとなるでしょう。コードの保守性を高め、エラーに強いシステムを構築することが、プロのVBAエンジニアへの第一歩です。日々の定型業務を、よりスマートに、より確実に自動化していきましょう。
