【Excel VBA】Dir関数でファイルやフォルダの存在をチェックする

アイキャッチ

ファイルやフォルダを操作するマクロを実行するとき、指定したファイルやフォルダがないと困るケースがあります。また、ファイルやフォルダの有無によって処理を分岐させたいケースもあると思います。

処理の事前にファイルやフォルダの存在チェックをする事でエラーを防いだり、処理を分岐させる事ができます。

今回は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

サンプルはドキュメントフォルダの拡張子xlsxファイルを全て表示します。「一致するファイル名が無い場合は長さ0の文字列“”を返す」をDo~Loopステートメント の条件にします。

3桁拡張子の罠

ワイルドカードで指定するとき*.xlsのように3桁拡張子を指定すると、前方一致の4桁拡張子もHITします(xlsxxlsm等)。どうも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

標準ファイルフォルダ

省略するとvbNormalになります。どの属性を指定しても標準ファイルは必ずセットで指定されます。

Public Sub Dir関数サンプル3()
    Dim ファイル名 As String
    
    ファイル名 = Dir("C:\Users\YOU\Documents\", vbHidden)
    
    Do While ファイル名 <> ""
        MsgBox (ファイル名)
        ファイル名 = Dir()
    Loop
End Sub

C:\Users\YOU\Documents\のようにパスの最後に\を付けるとそのフォルダ内のファイル全てが取得できます。

サンプルを実行すると、ドキュメントフォルダの標準ファイル隠しファイルが表示されます。が、使い勝手悪いです。ここを指定する人はきっと、属性別にファイル操作したい人のハズです。なぜ標準ファイルがもれなく付いてくるのでしょうか?

また、私の環境ではvbNormalを指定しても読み取り専用ファイルが一緒に抽出されます。隠しファイルはちゃんと除外されるのですが…

読み取り専用ファイル隠しファイル「のみ」抽出したい方は、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

ファイルチェックするコードはTrueを返す関数にし、別プロシージャ で呼び出す形にしています。

デモ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

フォルダの存在をチェックするコード

引数 attributesvbDirectoryを指定します。

サンプルは、ドキュメントフォルダ直下の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関数 を使用したサンプルを別記事で紹介しています。興味ある人は読んでみて下さい。

よかったらシェアしてね!
  • URLをコピーしました!
目次