ファイルを検索する


Excelは表計算ソフトですから表だけ計算してればいいんですが、ときには「何でExcelでそんなことまでするの?」ということもあります。まあ、Excelでゲーム作ったりしてる私が言えるセリフではありませんけど…。

それでも、Excelでちゃんとしたシステムを作ろうとしたら、表の計算以外にもたくさんの機能が必要になります。ここでは、ファイルを検索するテクをご紹介しましょう。きっと何かのときに役立つと思いますよ。

ファイルを検索するにはFileSearchオブジェクトを使います。厳密に言うとFileSearchオブジェクトはExcelのオブジェクトではなく、Officeシステム全体のオブジェクトです。ここでは、検索した結果をシートに出力していますが、UserFormを使っても便利ですね。

【追記】

Excel 2007からは、FileSearchオブジェクトが使えなくなりました。Excel 2007以降でファイルを検索する方法は、本コンテンツの後半をご覧ください。

Sub Sample()
    Dim f As Variant, buf As String, cnt As Long, FSO As Object
    Set FSO = CreateObject("Scripting.FileSystemObject")
    With Application.FileSearch
        .NewSearch
        buf = InputBox("検索するファイル名を指定してください")
        If buf = "" Or buf = "False" Then Exit Sub
        .Filename = buf
        buf = GetFolder("検索を開始するフォルダを指定してください")
        If buf = "" Then Exit Sub
        .LookIn = buf
        .SearchSubFolders = True        ''サブフォルダも検索する
        If .Execute() > 0 Then
            For Each f In .FoundFiles
                cnt = cnt + 1
                Cells(cnt, 1) = f                           ''パス+ファイル名
                Cells(cnt, 2) = FSO.GetFile(f).Name         ''ファイル名
                Cells(cnt, 3) = FSO.GetFile(f).ParentFolder ''パス
            Next f
        Else
            MsgBox "見つかりませんでした"
        End If
    End With
    Set FSO = Nothing
End Sub
Function GetFolder(msg As String)
    Dim Shell, myPath
    Set Shell = CreateObject("Shell.Application")
    Set myPath = Shell.BrowseForFolder(&O0, msg, &H1 + &H10)
    If Not myPath Is Nothing Then
        GetFolder = myPath.Items.Item.Path
    Else
        GetFolder = ""
    End If
    Set Shell = Nothing
    Set myPath = Nothing
End Function

FileSearchオブジェクトでファイルを検索するには、まずNewSearchメソッドを実行して前回の検索結果や条件をクリアします。これはお約束ですから、はじめて検索するときでも実行しておきましょう。

FileSearchオブジェクトは、検索するファイル名や検索する場所などをそれぞれプロパティに設定しておき、最後にExecuteメソッドで検索を実行します。Executeメソッドは見つかったファイルの個数を返しますので、返り値が0だったら見つからなかったということです。

Filenameプロパティには検索するファイル名を指定します。普通は「*.lzh」や「資料??.xls」のようにワイルドカードを指定しますね。いえ、もちろん「Book1.xls」と特定のファイルを探してもけっこうですけど。上記のサンプルでは、InputBoxを使って毎回ユーザーから検索するファイル名を受け取っています。InputBoxの詳細については、下記ページをご覧ください。

実は奥が深いInputBox

LookInプロパティは検索するフォルダを指定します。ここでは[フォルダを選択]ダイアログボックスで指定しています。[フォルダを選択]ダイアログボックスについては、下記ページをご覧ください。

フォルダを選択するダイアログボックス

同時に指定したいのはSearchSubFoldersプロパティです。SearchSubFoldersプロパティにTrueを指定すると、LookInプロパティに指定したフォルダ配下のフォルダもすべて検索します。

Executeメソッドで検索して見つかった結果は、FoundFilesプロパティで取得するFoundFilesオブジェクトに格納されます。FoundFilesオブジェクトはコレクションのように扱えますので、FoundFiles.Countで見つかったファイルの件数がわかります。個々のファイルにアクセスするにはFoundFiles(1)のようにインデックスを指定します。ただし、FoundFilesオブジェクトから得られるのは、見つかったファイルのフルパス+ファイル名だけです。「C:\My Documents\test\Book1.xls」のような形です。ここからファイル名だけを求めるのでしたらDir関数で一発なのですが、上記のサンプルではパス名なども抜き出しています。それにはFileSystemObjectオブジェクトを使いました。FileSystemObjectオブジェクトについては、下記ページをご覧ください。

FileSystemObjectオブジェクトの使い方

Excel 2007以降でファイルを検索する

Excel 2007から(正確には、Office 2007から)、FileSearchオブジェクトが使えなくなりました。Windows APIを使えば、ファイルを検索することもできますが、ここではFileSystemObjectを使ってみましょう。

一般的に、ファイルを検索するときは「あるフォルダから下のフォルダを探す」ことが多いです。たとえば、下図のようなフォルダがあったとします。

[Sample]フォルダは、C:\に作りましたので、C:\Sample\です。直下には[2009]フォルダと[2010]フォルダがあり、その下にもいくつかのフォルダがあります。それぞれのフォルダには、いろいろなファイルが、あったりなかったりします。たとえば、

みたいに。この「C:\Sampleフォルダから下のフォルダにあるブック」を探してみます。

FileSystemObjectを使うと、あるフォルダに存在するすべてのサブフォルダを取得できます。たとえば、次のようにします。

Sub FileSearch()
    Dim FSO As Object, Folder As Variant
    Set FSO = CreateObject("Scripting.FileSystemObject")
    For Each Folder In FSO.GetFolder("C:\Sample").SubFolders
        Debug.Print Folder.Path
    Next Folder
End Sub

あるいは、

Sub FileSearch()
    Dim FSO As Object, Folder As Variant
    Set FSO = CreateObject("Scripting.FileSystemObject")
    For Each Folder In FSO.GetFolder("C:\Sample\2009").SubFolders
        Debug.Print Folder.Path
    Next Folder
End Sub

この、サブフォルダを探すパスである GetFolder(■■■)の■■■を、引数で渡してみます。

Sub Sample()
    Call FileSearch("C:\Sample\2010")
End Sub

Sub FileSearch(Path As String)
    Dim FSO As Object, Folder As Variant
    Set FSO = CreateObject("Scripting.FileSystemObject")
    For Each Folder In FSO.GetFolder(Path).SubFolders
        Debug.Print Folder.Path
    Next Folder
End Sub

これを応用して、C:\Sampleフォルダから下にあるすべてのサブフォルダを探すには、次のように考えます。

  • まず、C:\Sampleフォルダ に存在するすべてのサブフォルダを探す
  • そこで見つかったサブフォルダ内に、さらにサブフォルダがないか探す

いずれにしても、サブフォルダを探すプロシージャは「Sub FileSearch(Path As String)」です。この「Sub FileSearch(Path As String)」内でサブフォルダを探し、見つかったサブフォルダに対して、また「Sub FileSearch(Path As String)」を実行します。このように、あるプロシージャが自分自身を呼び出す使い方を再帰と呼びます。

Sub Sample()
    Call FileSearch("C:\Sample")
End Sub

Sub FileSearch(Path As String)
    Dim FSO As Object, Folder As Variant
    Set FSO = CreateObject("Scripting.FileSystemObject")
    For Each Folder In FSO.GetFolder(Path).SubFolders
        Debug.Print Folder.Path
        Call FileSearch(Folder.Path)  ''見つかったフォルダを引数に指定して、自分自身を呼び出す
    Next Folder
End Sub

ここまでくれば、あとは簡単です。それぞれのフォルダに保存されている、すべてのファイルを調べればいいんです。フォルダ内の全ファイルは、Filesコレクションで取得できます。まずは、すべてのファイル名を出力してみましょうか。

Sub Sample()
    Call FileSearch("C:\Sample")
End Sub

Sub FileSearch(Path As String)
    Dim FSO As Object, Folder As Variant, File As Variant
    Set FSO = CreateObject("Scripting.FileSystemObject")
    For Each Folder In FSO.GetFolder(Path).SubFolders
        Call FileSearch(Folder.Path)
    Next Folder
    For Each File In FSO.GetFolder(Path).Files
        Debug.Print File.Path
    Next File
End Sub

Excelのブックだけ取得するときは、ファイルのTypeプロパティを調べましょう。インストールされているExcelのバージョンによって異なる場合もありますが、Excel 2007の環境では、Typeプロパティは次の文字列を返します。

  • 2003形式のブック → Microsoft Office Excel 97-2003 ワークシート
  • 2007形式のブック → Microsoft Office Excel ワークシート
Sub Sample()
    Call FileSearch("C:\Sample")
End Sub

Sub FileSearch(Path As String)
    Dim FSO As Object, Folder As Variant, File As Variant
    Set FSO = CreateObject("Scripting.FileSystemObject")
    For Each Folder In FSO.GetFolder(Path).SubFolders
        Call FileSearch(Folder.Path)
    Next Folder
    For Each File In FSO.GetFolder(Path).Files
        If InStr(File.Type, "Excel") > 0 Then
            Debug.Print File.Path
        End If
    Next File
End Sub

すべてのファイルを探すには、このようにすればいいですね。もちろん、ある特定のブックを探すのなら、たとえば次のようにします。ここでは「Book1.xlsx」を探してみましょう。

Sub Sample()
    Call FileSearch("C:\Sample")
End Sub

Sub FileSearch(Path As String)
    Dim FSO As Object, Folder As Variant, File As Variant
    Set FSO = CreateObject("Scripting.FileSystemObject")
    For Each Folder In FSO.GetFolder(Path).SubFolders
        Call FileSearch(Folder.Path)
    Next Folder
    For Each File In FSO.GetFolder(Path).Files
        If File.Name = "Book1.xlsx" Then
            Debug.Print File.Path
        End If
    Next File
End Sub

汎用性を高めるなら、最初に実行する「Sub Sample」から、探すブック名を指定できるようにします。

Sub Sample()
    Call FileSearch("C:\Sample", "Book1.xlsx")
End Sub

Sub FileSearch(Path As String, Target As String)
    Dim FSO As Object, Folder As Variant, File As Variant
    Set FSO = CreateObject("Scripting.FileSystemObject")
    For Each Folder In FSO.GetFolder(Path).SubFolders
        Call FileSearch(Folder.Path, Target)
    Next Folder
    For Each File In FSO.GetFolder(Path).Files
        If File.Name = Target Then
            Debug.Print File.Path
        End If
    Next File
End Sub

ブック名を、完全一致ではなく、部分一致で検索するときは、次のようにLike演算子を使いましょう。

Sub Sample()
    Call FileSearch("C:\Sample", "2009-??.xls*")
End Sub

Sub FileSearch(Path As String, Target As String)
    Dim FSO As Object, Folder As Variant, File As Variant
    Set FSO = CreateObject("Scripting.FileSystemObject")
    For Each Folder In FSO.GetFolder(Path).SubFolders
        Call FileSearch(Folder.Path, Target)
    Next Folder
    For Each File In FSO.GetFolder(Path).Files
        If File.Name Like Target Then
            Debug.Print File.Path
        End If
    Next File
End Sub

ということで、FileSystemObjectを使ってファイルを検索するやり方を解説したわけですが、かんじんなのは「検索して見つかったファイルをどうするか」です。これはもう、業務によって千差万別です。見つかったファイルをExcelで開くのかもしれないし、別のフォルダに移動したり、削除したり、名前を変えるかもしれません。移動するフォルダは、見つかったファイルの名前によって異なるかもしれませんし、すべてを連番の名前にリネームするのかもしれません。

そうした「見つかったファイルにすること」は、上記の「Debug.Print File.Path」部分を書き換えればいいのですが、実はそれも、ビギナーには荷が重いです。一般的に、業務で使用するマクロは、ファイルを検索して終わりではありません。「ファイルを見つけて○○する」のが目的でしょう。この「ファイルを見つけて」は、上記で解説したようにすれば可能です。しかし「○○する」の部分は、また別の技術や知識が必要になります。さらに、この手の、別ファイルを操作するようなマクロでは、いろいろなケースに対応したエラー対策も必須になります。したがって「ファイルを見つけて○○する」ような実務的なマクロを作成するには、ちゃんとVBAを学習しなければならない、ということです。もちろんそれは、ファイルの検索に限った話ではありませんけどね。