hakeの日記

Windows環境でプログラミングの勉強をしています。

EXCEL VBAメモ - DIR関数のハマりどころ

デバッグで少々ハマったのでメモ。

指定したフォルダの下のファイルを一つずつ取り出して処理する場合や、特定のファイルが存在するかを判断したい場合には、DIR関数で簡潔に記述できるのでよく使用します。こんな感じで

    Dim path As String
    Dim file As String
    
    path = "c:\foo"
    file = Dir(path & "\*.xml")
    Do Until file = ""
    
        Debug.Print file
        
        file = Dir()
    Loop


ところがDIR関数を使用したループ内では、そのループ用途以外ではDIR関数が使用できないという問題があります。
下の例では、DIR関数を使用したループ内で、更にファイルの存在確認にDIR関数を使用しています。このような使い方をした場合には、実行時にループの最後の

    file = Dir()

で、「プロシージャの呼び出し、または、引数が不正です」というエラーが発生します。

    Dim path As String
    Dim file As String
    
    path = "c:\foo"
    file = Dir(path & "\*.xml")
    Do Until file = ""
    
        If Dir("c:\foo.txt") <> "" Then
            Debug.Print "Exist"
        End If
        Debug.Print file
        
        file = Dir()           'ここでエラー
    Loop


上の例の様にループの中で、別の用途のDIR関数を直接記述した場合には直ぐにわかります。
ところがループの中でプロシージャを呼び出していて、そのプロシージャの中(または更に呼び出されるプロシージャの中)でDIR関数を使用した場合には、呼び出されるプロシージャの単体のテストでは問題なく動作してしまう為、見つけるのが難しくなってしまいます。


その様なことを防止するためにも指定フォルダの下のファイルを一つずつ処理するような場合には、少々記述が面倒になりますが FileSystemObject を使用した方が良いと思われます。

    Dim fso As Object
    Dim file As Object
    Dim path As String
    
    path = "c:\foo"
    Set fso = CreateObject("Scripting.FileSystemObject")
        
    For Each file In fso.GetFolder(path).Files
        If Right(file.Name, 4) <> ".xml" Then GoTo Continue
    
        If Dir("c:\foo.txt") <> "" Then
            Debug.Print "Exist"
        End If
        Debug.Print file.Name
Continue:
    Next