【エクセルVBA】複数階層フォルダを一括作成する(Win32API – MakeSureDirectoryPathExists)

ファイル保存するときに「MkDir」で保存先フォルダも作成するようにしたけど、フォルダが既に存在しているとエラーになるし、一度に複数階層の作成はできないみたいだし、思ったより面倒だな。

「MkDir」や「FileSystemObject – CreateFolder」だと、フォルダの存在チェックが必要だし、複数階層のフォルダ作成は工夫しないとできないわね。

複数階層を作る場合は、
 パスからフォルダ名を抽出
→上位フォルダから順番に存在チェック
→存在していなければフォルダ作成
→以上をフォルダ数の分だけ繰り返し
といった感じに自分で実装すればできそうですけど、もっと簡単にできないですかね。

VBAからWindowsAPIの関数を呼び出して、複数階層フォルダを一括作成する方法があるけど。

それは楽そうですね、どうやるんですか?

ということで、複数階層フォルダの一括作成について紹介していきます。

はじめに

フォルダの作成は「MkDir」や「FileSystemObject – CreateFolder」を使えば簡単にできますが、厄介なのが複数階層(多階層、深い階層)のフォルダを作成したい場合です。

親フォルダから順番に作成していかねばならず、さらにそのフォルダが既に存在している場合はエラーになるので、存在チェックもしなければいけません。

もちろん「MkDir」を使って実装できますが、ちょっと手間が掛かりますね。

そこで、Windowsにあらかじめ備わっている「Win32API – MakeSureDirectoryPathExists」をVBAから使用することで、フォルダの存在チェックなどなしに、複数階層のフォルダを一括作成してみます。

ソースコード

'動的リンクライブラリ(DLL)内の外部プロシージャへの参照を宣言
Private Declare PtrSafe Function MakeSureDirectoryPathExists Lib "imagehlp.dll" (ByVal lpPath As String) As Long

'-----------------------------------------------------------------------
'フォルダを作成する
'-----------------------------------------------------------------------
Public Function MakeFolder(folderPath As String) As Long
    'フォルダ作成に成功(または既に存在している):1を返却
    'フォルダ作成に失敗:0を返却
    MakeFolder= MakeSureDirectoryPathExists(folderPath & "\")    'パスの末尾に「\」を付ける
End Function

テストコード

Sub Test()
    '作成する複数階層のフォルダパス
    Const folderPath As String = "C:\00_myenv\10_macro\05_tmp\test1\test2\test3"
    
    If MakeFolder(folderPath) = 1 Then
        Debug.Print "フォルダ作成 成功(または既に存在している)"
    Else
        Debug.Print "フォルダ作成 失敗"
    End If
End Sub

実行結果

実行前
実行結果(実行前のフォルダ状態)
実行後
実行結果(実行後のフォルダ状態)
実行結果メッセージ

説明

「Win32API」を使用するには、ソースコードの先頭部分に「Declare」でDLL内の外部プロシージャへの参照を宣言する必要があります。

Declare ステートメント (VBA)
Declare ステートメント (VBA) の使用方法について説明します

今回は「Win32API – MakeSureDirectoryPathExists」を使用するので、ソースコードの2行目のような記載をすることになります。

これはお決まりのものなので、そのまま記載すればよいです。

あとは作成したいフォルダパスを引数に指定して「MakeSureDirectoryPathExists」を呼び出すだけです。

テストコードでは複数階層のフォルダを作成していますが、当然ですが、フォルダ1つ作成したい場合でも使えます。

注意点として、パスの末尾には円マーク「\」を付けるのを忘れないようにしてください。

末尾に円マークがいていないと、最終フォルダの親フォルダまでしか作成されません。

テストコードで言うと、「test2」のフォルダまでは作成されますが、「test3」が作成されなくなってしまいます。

ちなみに、円マークが「\\」と連続しても問題ないようなので、ソースコードでは末尾に固定で円マークを付けています。

また、フォルダが既に存在している場合でも「成功」となるので、「存在していなければ作成する」といった考慮は必要ありません。

以上のように、「MakeSureDirectoryPathExists」は複数階層フォルダを作成する際には、非常に便利な関数です。

冒頭のやり取りにもありますが、「MkDir」で複数階層フォルダを作成する場合、

  パスからフォルダ名を抽出
→ 上位フォルダから順番に存在チェック
→ 存在していなければフォルダ作成
→ 以上をフォルダ数の分だけ繰り返し

といった一連の処理を自分で実装しなければなりません。

それに比べて「MakeSureDirectoryPathExists」は宣言部分を除けば、わずか1行で済みます。

また、Win32APIの関数を使用するので、バグの心配もありません。

同じく複数階層フォルダを一括作成できるものとして「Win32API – SHCreateDirectoryEx」というものがあり、こちらはフォルダが既に存在している場合を区別できる返却値があるようなので、既に存在している場合に何か処理をしたい場合は、こちらを使用する方がよいかもしれません。

この記事では紹介しませんが、ググればすぐ見つかると思います。

まとめ

以上、「MakeSureDirectoryPathExists」による複数階層フォルダ作成について紹介しました。

  • 上位フォルダから順番に作成、フォルダの存在チェックなど、自分で実装をしないで済む
  • Win32APIを使用するので、バグが入る可能性が低くなる
  • ソースコードが短くて済む

などの利点があると思います。

関数などで既に提供されている機能と同じものを、自分で試行錯誤して頑張って作ることで、プログラミングスキルが上達することはあると思います。

ですが、それは逆に言えば「しなくてもよい実装をしている」とも言えます。

コード量が増えるということは、それだけバグが入る可能性が増えるということでもあります。

試行錯誤して実装することが悪いこととは思いませんが、出来上がったコードがなんだか複雑になってしまったなと思ったら、既に存在しているシンプルな方法はないものか、と探してみるのもよいのではないでしょうか。

以上、ご覧いただきありがとうございました。