フォルダ配下(サブフォルダも)ファイル一覧を取得するには【CMD】【ExcelVBA】

コマンドプロンプトとVBAで、フォルダ配下のすべてのファイルの一覧を取得する方法を紹介します。

環境

こういうフォルダ構成の環境があったとします。

C:\test>tree /f
フォルダー パスの一覧:  ボリューム Windows-SSD
ボリューム シリアル番号は D0EF-3D22 です
C:.
│  results-001-タイプAとタイプBを比較.pptx
│  results-002-タイプAとタイプCを比較.pptx
│  results-003-タイプBとタイプCを比較.pptx
│  results-004-タイプCとタイプDを比較.pptx
│  test.jpg
│
└─Sub1
    │  果物.xlsx
    │
    └─Sub2
            aaaa.txt

C:\test配下にあるすべてのファイル(サブフォルダ含む)を取得する方法について説明します。

コマンドプロンプト

コマンドプロンプトでやる場合には、Dirコマンドを使います。

dir /b/a:-D/s

/bでパスだけを表示(ファイルサイズや更新日等を表示しない)し、/a:-Dでディレクトリを除きファイルだけを表示し、/sでサブフォルダも検索するという意味になります。

以下は実行してみたところ。

C:\test>dir /b/a:-D/s
C:\test\results-001-タイプAとタイプBを比較.pptx
C:\test\results-002-タイプAとタイプCを比較.pptx
C:\test\results-003-タイプBとタイプCを比較.pptx
C:\test\results-004-タイプCとタイプDを比較.pptx
C:\test\test.jpg
C:\test\Sub1\果物.xlsx
C:\test\Sub1\Sub2\aaaa.txt

VBA

ExcelVBAでやる場合、Dirを使う方法もありますが、私はFIleSystemObjectを使って再帰検索する方法が割と好きでよく使います。

Option Explicit

Public Sub GetFileList()
    Dim FSO As Object
    Set FSO = CreateObject("Scripting.FileSystemObject") '---①
    
    Dim stFiles As Collection
    Set stFiles = New Collection
    
    Dim oFolder As Object
    Set oFolder = FSO.GetFolder("C:\test")
    
    Call GetFileRe(oFolder, stFiles)
    
    If stFiles.Count > 0 Then
        Dim vOut() As Variant, ii As Long     '---②
        ReDim vOut(1 To stFiles.Count)        '---②
        For ii = LBound(vOut) To UBound(vOut) '---②
            vOut(ii) = stFiles(ii)            '---②
        Next ii
        With ThisWorkbook.Worksheets(1)
            .Cells(2, 2).Resize(UBound(vOut), 1).Value = WorksheetFunction.Transpose(vOut)
        End With
    End If
    
    Set oFolder = Nothing
    Set FSO = Nothing
    Set stFiles = Nothing
End Sub

Private Sub GetFileRe(oFolder As Object, ByRef stFiles As Collection)
    Dim oFol As Object
    Dim oFile As Object
    
    '---③ ここでFSOをクリエイトしない
    
    For Each oFol In oFolder.SubFolders
        '再帰呼出
        Call GetFileRe(oFol, stFiles) '---④
    Next oFol
    
    For Each oFile In oFolder.Files
        'コレクションに追加
        stFiles.Add oFile.path, oFile.path
    Next oFile
End Sub

①、③の解説

Webを検索していると、CreateObjectを③に記述しているコードを見かけるのですが、再帰呼出されるサブ関数の中でオブジェクトをCreateすることが、私はノイジーに感じてしまうので、①の位置でCreateしました。

②の解説

検索して得た情報をどうやってアウトプットするかですが、Cellsにそのまま書き出すのも一つの手ですが、Cellsに書き出す場合、1レコードを1書き出しというやり方をするのはどうしてものろく感じるので、全部のレコードを一度に1回だけCellsに書き出す方法を採用しています。

そのため、いったんメモリ上のvOutという配列に、コレクションの値を書き出しています。

④の解説

再帰呼出しています。

再帰呼出はネストが深くなるとメモリオーバフロを起こすことがあります。私が経験した環境では、ネストの深さより、ファイル名の長さの方がネックでした(256文字以上のファイル名が存在した)。

そのときは、その長いファイル名だけは飛ばして処理をするようにし、手動でそのファイルだけをあとで付け加えることにしました。自動でなんとかするのは無理でした。

まとめ

ファイル一覧を作成する方法を二つ紹介しました。

ファイル一覧を作成するのは、実務ではほとんどの場合、コマンドプロンプトでやっていました。

dir /s/b/a:-D > list.txt

というように、テキストにリダイレクトして使っていました。

サブフォルダも検索してくれるのがコマンドプロンプトの強みですね。

サブフォルダを検索する必要がなければ、GUIでもできます。

エクスプローラーでファイル名を全部選択し、Shiftキーを押しながら右クリックしてパスのコピーを選べば、ファイル名一覧を取得できます。

Shiftキーを押しながら右クリック→パスのコピー

何かの参考になれば幸いです。