ファイルやフォルダを操作するマクロを実行するとき、指定したファイルやフォルダがないと困るケースがあります。また、ファイルやフォルダの有無によって処理を分岐させたいケースもあると思います。
処理の事前にファイルやフォルダの存在チェックをする事でエラーを防いだり、処理を分岐させる事ができます。
今回はDir関数 を使ってファイルやフォルダの存在をチェックします。
Dir関数
Dir(pathname(省略可能),[attributes(省略可能)])
引数 pathname
Dir関数 は、引数 pathnameに指定したパスから、最初のファイル名(パスを含まないファイル名のみ)を返します。一致するファイル名が無い場合は長さ0の文字列“”を返します。
Public Sub Dir関数サンプル1()
Dim ファイル名 As String
ファイル名 = Dir("C:\Users\YOU\Documents\test.xlsx")
If ファイル名 <> "" Then
MsgBox (ファイル名)
Else
MsgBox ("ファイルが存在しません")
End If
End Sub
サンプルはファイルが存在した場合、パスを含まないファイル名を表示します。存在しない場合は“”を返すので「ファイルが存在しません」が表示されます。
要は指定したパスが存在しなくてもエラーにはなりません。但し、pathnameに空白” “を指定するとエラーになります。
ワイルドカード
pathnameにはワイルドカードを指定できます(Macは不可)。複数文字は*、一文字は?で指定します。前述の最初のファイル名とはワイルドカードで指定した場合、「一致するファイルが複数あったときに最初に抽出されたファイル名」の意味になります。
Dir関数 を一度実行した後であればpathnameは省略可能です。Dir()で前回と同じ引数で再検索し、一致した次のファイル名を返します。但し、前回の実行で一致するファイルが無かった場合(長さ0の文字列“”を返した直後)、あるいは一度目の実行でpathnameを省略した場合はエラーになります。
Public Sub Dir関数サンプル2()
Dim ファイル名 As String
ファイル名 = Dir("C:\Users\YOU\Documents\*.xlsx")
Do While ファイル名 <> ""
MsgBox (ファイル名)
ファイル名 = Dir()
Loop
End Sub
3桁拡張子の罠
ワイルドカードで指定するとき*.xlsのように3桁拡張子を指定すると、前方一致の4桁拡張子もHITします(xlsx、xlsm等)。どうもWindowsの仕様らしいですが、3桁拡張子でパスを指定する場合は注意が必要です。回避方法はググると出てきます。
パス長の制限(があるらしい)
そもそもWindowsにはパス長の制限があるようです(Windows10の場合、フォルダパスで247文字、ファイル名含むフルパスで259文字らしい)。テストで長いフォルダ名にしてみたところ、一定の文字数(文字数は確認していません)を超えると「フォルダ名が長すぎる」とWindowsに怒られだします。
怒られないギリギリの文字数でマクロを実行してもVBAには怒られませんでした。
他サイトを調べる限りでは、パス制限について言及しているサイトのほとんどが「Dir関数 (のpathname)には256バイト制限がある」と書いています。
私はWindowsに怒られずにVBAで制限にひっかかるケースを再現できていないので、知識として頭の片隅に置いています。
まぁきっと、この引用部分が答えなんでしょうね。
256バイトを超えるパス名が扱えない
これは、そもそもWindowsとしての制限もあるので、ローカルのPC内の処理では通常は問題が出ないはずです。
https://excel-ubara.com/excelvba4/EXCEL262.html
引数 attributes
attributesには次の属性が指定できます。
- vbNormal
(規定値)属性のないファイル。読み取り専用でも隠しファイルでもない標準ファイルです。
- vbReadOnly
標準ファイルと読み取り専用ファイル。ファイルのプロパティ で設定する読み取り専用にチェックが入ったファイルです。
- vbHidden
標準ファイルと隠しファイル。プロパティの隠しファイルにチェックが入ったファイルです。
- vbSystem
標準ファイルとシステムファイル。OSにまつわるファイルです。
- vbVolume
標準ファイルとボリュームラベル。ストレージの記憶領域やメディアに付けられた名前です。
- vbDirectory
標準ファイルとフォルダ。
Public Sub Dir関数サンプル3()
Dim ファイル名 As String
ファイル名 = Dir("C:\Users\YOU\Documents\", vbHidden)
Do While ファイル名 <> ""
MsgBox (ファイル名)
ファイル名 = Dir()
Loop
End Sub
C:\Users\YOU\Documents\のようにパスの最後に\を付けるとそのフォルダ内のファイル全てが取得できます。
読み取り専用ファイルや隠しファイル「のみ」抽出したい方は、GetAttr関数 (pathnameを返す関数)でググって下さい。
ファイルの存在をチェックするコード
Public ファイルチェック(ByVal ファイル_パス As String) As Boolean
Dim ダイアログ As Long
If Dir(ファイル_パス) <> "" Then
ダイアログ = MsgBox("ファイルが既に存在します。" & vbCrLf & "〇〇しますか?", vbYesNo)
Select Case ダイアログ
Case vbYes
Exit Function
Case vbNo
MsgBox "処理を中止しました"
ファイルチェック = True
End Select
End If
End Function
Public Sub デモ1()
If ファイルチェック("C:\Users\YOU\Documents\test.xlsx") Then Exit Sub
MsgBox "〇〇しました" 'Yesの処理を記述
End Sub
デモ1の初っ端にファイルの存在を確認、存在する場合はデモ1を継続する/しないの2択、存在しなければそのままデモ1を継続するコードです。
プロシージャ を分割しない場合はこのコードでおおよそ同じ挙動になります。
Public Sub デモ2()
Dim ダイアログ As Long
If Dir("C:\Users\YOU\Documents\test.xlsx") <> "" Then
ダイアログ = MsgBox("ファイルが既に存在します。" & vbCrLf & "〇〇しますか?", vbYesNo)
Select Case ダイアログ
Case vbYes
MsgBox "〇〇しました"
Case vbNo
MsgBox "処理を中止しました"
End Select
Else
MsgBox "〇〇しました"
End If
End Sub
フォルダの存在をチェックするコード
引数 attributesにvbDirectoryを指定します。
サンプルは、ドキュメントフォルダ直下のTESTフォルダ有無を確認、無ければフォルダを作成する/しないの2択、そもそも存在する場合は処理が何も発生しないコードです。
Public Function フォルダチェック(ByVal フォルダ_パス As String) As Boolean
Dim ダイアログ As Long
If Dir(フォルダ_パス, vbDirectory) = "" Then
ダイアログ = MsgBox("保存用フォルダ「" & フォルダ_パス & "」がありません。作成しますか?", vbYesNo)
Select Case ダイアログ
Case 6
MkDir フォルダ_パス 'MkDirステートメント…フォルダ作成
MsgBox "フォルダ「" & フォルダ_パス & "」を作成しました"
Exit Function
Case 7
MsgBox "処理を中止します"
フォルダチェック = True
End Select
End If
End Function
Public Sub デモ3()
If フォルダチェック("C:\Users\YOU\Documents\TEST") Then Exit Sub
End Sub
「ファイルの存在をチェックするコード」と同様で関数化していますが、少し挙動が違います。
「ファイルの存在をチェックするコード」はファイルが有る時は2択、無いときは処理を実行します。「フォルダの存在をチェックするコード」はフォルダが無い時は2択、有るときは処理が何もないコードです。関数内に処理を含めるかどうかで挙動を変えることができます。
メインのプロシージャ での可読性や関数(チェックするコード)の範疇をどこまでにするのかで書き分けるようになると思います。
Dir関数 を使ったファイルやフォルダの存在確認方法を紹介しました。ここでは紹介していませんが、FileSystemObjectオブジェクト (Microsoft Scripting Runtimeライブラリ のクラス です)を使用して、より高度な処理も可能です。
Dir関数 を使用したサンプルを別記事で紹介しています。興味ある人は読んでみて下さい。