2016/06/06

[ VBA ] 指定フォルダ以下の全フォルダに含まれるファイルの一覧を取得したい

カテゴリー:
タグ:

VBAで、あるフォルダの中にあるファイルの一覧を取得したい場合に、どう書けばいいかを解説します。VBAでフォルダの操作をすることはちょくちょくあるのですが、すぐに忘れてしまう自分へのメモです。

事前準備

VBAでフォルダやファイルを扱う場合、FileSystemObjectオブジェクトを使います。まずは、これを扱いやすくするために、参照設定を行います。

Visual Basic Editorを立ち上げ(Alt+F11)、メニューのツール⇒参照設定を選択します。そこから「Microsoft Scripting Runtime」を探し出してチェックを入れます。すると、scrrun.dllへのパスが表示され、参照設定が完了です。

フォルダ内のファイル一覧を取得する

まずは、フォルダを指定したときに、そこに含まれるファイルの一覧を取得してみます。

Sub getFileList()

    Dim fso As New FileSystemObject, myFile As File, myCount As Long
    
    For Each myFile In fso.GetFolder("C:\").Files
    
        myCount = myCount + 1
        Cells(myCount, 1) = myFile.Name
        
    Next
    
End Sub

この数行で、Cドライブ直下にあるファイル一覧が、A列に表示されます。

Dim fso As New FileSystemObject

の部分で、FileSystemObjectオブジェクトを使えるようにしているんですね。「fso.GetFolder(“C:\”)」では、GetFolderを使って、指定したフォルダのFolderオブジェクトを取得しています。そして、For Eachの中で各ファイルの名前を取得しています。

なお、参照設定をしていなかった場合は、変数宣言のところを次のように変えないといけません。

Sub getFileList2()

    Dim fso As Object, myFile As Object, myCount As Long
    
    Set fso = CreateObject("Scripting.FileSystemObject")
    
    For Each myFile In fso.GetFolder("C:\").Files
    
        myCount = myCount + 1
        Cells(myCount, 1) = myFile.Name
        
    Next
    
End Sub

型がただのObjectになっています。コード補完などが効かないので、不便です。参照設定をするほうが楽になることが分かりますね。

ダイアログで指定したフォルダの中のファイル一覧を取得する

コード内でフォルダを指定するのではなく、マクロを実行するたびにフォルダを選択したいという場合もあるでしょう。そういうときはこのようにします。

Sub getFileListFromDialog()

    Dim fso As New FileSystemObject, myFile As File, myCount As Long
    
    With Application.FileDialog(msoFileDialogFolderPicker)
    
        If Not .Show Then Exit Sub
        
        For Each myFile In fso.GetFolder(.SelectedItems(1)).Files
        
            myCount = myCount + 1
            Cells(myCount, 1) = myFile.Name
            
        Next
        
    End With
    
End Sub

違っているのは、

With Application.FileDialog(msoFileDialogFolderPicker)

の部分などですね。こう書くと、フォルダを指定するためにダイアログが開きます。このダイアログでフォルダが指定されれば、そのフォルダのパスを「.SelectedItems(1)」で取得し、先ほどと同じ要領でファイルの一覧を取得していきます。

ダイアログでキャンセルボタンが押されたときは、「.Show」に0が返されるので、そのときは「Exit Sub」、つまり、終了するようにしています。

フォルダ一覧も欲しい

フォルダに含まれるファイル名だけでなく、その直下にあるフォルダの一覧も欲しいという場合には、次のようにします。

Sub getFolderAndFileListFromDialog()

    Dim fso As New FileSystemObject, myFolder As Folder, myFile As File, myCount As Long
    
    With Application.FileDialog(msoFileDialogFolderPicker)
    
        If Not .Show Then Exit Sub
        
        For Each myFolder In fso.GetFolder(.SelectedItems(1)).SubFolders
        
            myCount = myCount + 1
            Cells(myCount, 1) = myFolder.Name
            
        Next
        
        For Each myFile In fso.GetFolder(.SelectedItems(1)).Files
        
            myCount = myCount + 1
            Cells(myCount, 1) = myFile.Name
            
        Next
        
    End With
    
End Sub

追加したところで重要なのは、

For Each myFolder In fso.GetFolder(.SelectedItems(1)).SubFolders

ですね。フォルダ内のフォルダは、「SubFolders」を使って取得します。

指定フォルダ以下の全フォルダに含まれるファイルの一覧を取得したい

あるフォルダ内のファイルだけでなく、そのフォルダに含まれるすべてのフォルダについて、ファイルの一覧が欲しいという場合もあるでしょう。フォルダの数が多いと時間がかかりすぎて固まる可能性があるので注意が必要ですが、次のように書いて「getFolderAndFileListFromDialogMain」を実行すればやりたいことが実現できます。

Sub getFolderAndFileListFromDialogMain()

    With Application.FileDialog(msoFileDialogFolderPicker)
    
        If Not .Show Then Exit Sub
        
        Call getFolderAndFileListFromDialogSub(folderPath:=.SelectedItems(1))
        
    End With
    
End Sub

Sub getFolderAndFileListFromDialogSub( _
        folderPath As String, Optional myCount As Long = 0)

    Dim fso As New FileSystemObject, myFolder As Folder, myFile As File
    
    For Each myFile In fso.GetFolder(folderPath).Files
    
        myCount = myCount + 1
        Cells(myCount, 1) = myFile.Path
        
    Next
    
    For Each myFolder In fso.GetFolder(folderPath).SubFolders
    
        Call getFolderAndFileListFromDialogSub(myFolder.Path, myCount)
        
    Next

End Sub

サブフォルダ内のファイルリストを作成するために、「フォルダを指定したら、ファイル一覧を作成する」という機能(Subの方)を作りました。これを各サブフォルダごとに呼び出す、という方法をとっています。再帰的にファイル一覧の作成を行っているということです。Mainの方は、リストを作る出発地点のフォルダを指定するのが主な役割となっています。

サブフォルダも対象にするとなると、ファイル名ではなくてファイルのパスまで見ないと意味がなくなってくるので、「myFile.Name」は「myFile.Path」に変えています。

まとめ

書き方自体は難しくなく、決まったことしか書かないのですが、使う場面が限られているのでなかなか覚えられません。ただ、たいていのことはこの記事に書いたことを応用すればできるんじゃないかと思います。

さて、今、ココナラというサービスで、エクセルやVBAの相談を受けつけています。案件によりますが、500円から受け付けています。よろしくお願いします!

エクセルマクロ、エクセル関数のこと、ご相談ください!

前の記事:
次の記事: