フォルダが存在するか調べる方法を解説します。
Dir関数の引数にvbDirectoryを渡して判定するか、
FileSystemObjectのFolderExistsメソッドを使用します。
Dir関数(vbDirectory)による判定
フォルダが存在するかどうかは、
Dir関数の引数に判定フォルダパスとvbDirectoryを渡すと判定できます。
Dim 判定フォルダパス As String 判定フォルダパス = "C:\Users\wfsp\Desktop\テストフォルダ" If Dir(判定フォルダパス, vbDirectory) = "" Then MsgBox "指定のフォルダが存在しません。" End If
If文の判定が「=""」であることを見るとわかりますが、
Dir関数の結果はTrue/Falseではありません。
- フォルダが存在する場合は「フォルダ名」(サンプルでは"テストフォルダ")
- フォルダが存在しない場合は""
という仕様になりますので、Dir関数によるフォルダの存在判定は「=""」「<>""」のどちらかで行うことになります。
例えば「フォルダがなければ作成してからブックを保存」する処理は、
以下のように記述します。
Dim 保存フォルダパス As String 保存フォルダパス = ThisWorkbook.Path & "\出力フォルダ" If Dir(保存フォルダパス, vbDirectory) = "" Then MkDir 保存フォルダパス End If 出力ブック.SaveAs 保存フォルダパス & "\~~~~.xlsx"
すべてのファイルを調べるコードと併用不可
上記のコードは簡潔なのですが、Dir関数には注意すべき仕様があります。
簡単に言うと「すべてのファイルを調べるコード」との併用ができません。
例えばこんなコードを書いたとします。
' すべてのファイルを調べるDoループ Dim dirファイル名 As String dirファイル名 = Dir(調査フォルダパス & "\*.xlsx") ' Dir① Do While dirファイル名 <> "" ~~~ここにファイルごとの処理 ' フォルダがなければ作成した上でブックを保存する処理 If Dir(保存フォルダパス, vbDirectory) = "" Then ' Dir② MkDir 保存フォルダパス End If 出力ブック.SaveAs 保存フォルダパス & "\~~~~.xlsx" dirファイル名 = Dir() ' ←このDirは①ではなく②を見てしまう Loop
Dir関数によってフォルダ内のすべてのファイルを調べるコードは、
「引数なしのDir()は、ひとつ前のDir関数の続きを実行する」
という性質を利用しています。
しかしこのコードでは、
「ひとつ前のDir」がフォルダの存在判定をしたDirに上書きされてしまうんですね。
そのせいでこのコードは全ファイルを処理できません。
なかなか複雑で見落としやすいポイントになりますので気を付けましょう。
この対策として、フォルダが存在するかを調べるコードをFileSystemObjectに書き換える必要があります。
FileSystemObjectのFolderExistsメソッドで判定する
フォルダの存在判定は、FileSystemObjectオブジェクトのFolderExistsメソッドを使って行うこともできます。
FileSystemObjectそのものの解説はここでは省略しますので、
- 複雑なファイル操作を行う予定がある人は別所でしっかり学習
- 今この問題が解決できれば良い人はまるごとコピペ
で対応してください。
FileSystemObject(以下FSO)を使用したフォルダ判定コードがこちらです。
Dim FSO As Object Set FSO = CreateObject("Scripting.FileSystemObject") if FSO.FolderExists(保存フォルダパス) = False Then MkDir 保存フォルダパス End If
FSOの宣言部が少し面倒になりますが、
判定がTrue/Falseになるのはわかりやすくていいですね。
このコードであれば、Dir関数を使ったループ中でも問題なくフォルダの存在判定を行うことができます。
Dir関数をファイル走査によく使う方は、この書き方も覚えておいてください。
余談ですが、せっかくFSOを使用(インスタンス化)していますので、
MkDir 保存フォルダパス ' ↓フォルダ作成もFSOに書き換え FSO.CreateFolder 保存フォルダパス
こちらも書き換え可能です。
フォルダの作成ではMkDirとFSOは全く同じ動きをしますので、
どちらを使うかは好みでOKです。
汎用関数化
上記の通り、Dir関数で行うフォルダ判定は簡潔ですが罠があり、
しかしFSOでのフォルダ判定は安定しますがコードが面倒です。
これを解決するには、FSOを1行で実行できるよう、
汎用関数にして持っておきましょう。
' 汎用関数 Function Isフォルダが存在する(フォルダパス As String) As Boolean Dim FSO As FileSystemObject Set FSO = CreateObject("Scripting.FileSystemObject") Isフォルダが存在する = FSO.FolderExists(フォルダパス) End Function ' 実行例 If Isフォルダが存在する(保存フォルダパス) = False Then MkDir 保存フォルダパス End If
これでOKです。
↓この部分が難しく感じた方は、
Isフォルダが存在する = FSO.FolderExists(フォルダパス)
↓これと同じ処理ですので読み解いてみてください。
If FSO.FolderExists(フォルダパス) = True Then Isフォルダが存在する = True Else Isフォルダが存在する = False End If
この関数であれば1行で書けるうえに、
コードがDir関数の実行中であるかは気にする必要がありません。
このようにちょっとした処理を関数化しておくと、
コードが書きやすく、そして読みやすくなります。
よく書くコードは、汎用関数にして持っておきましょう。