名前を指定してブックを開く


開くブックをユーザーに選択してもらう場合は、[ファイルを開く]ダイアログボックスを表示するといいでしょう。

Sub Sample1()
    Dim OpenFileName As String
    OpenFileName = Application.GetOpenFilename("Microsoft Excelブック,*.xls?")
    Workbooks.Open OpenFileName
End Sub

[ファイルを開く]ダイアログボックスを表示するには、ApplicationオブジェクトのGetOpenFilenameメソッドを使います。GetOpenFilenameメソッドによる[ファイルを開く]ダイアログボックスは、ユーザーが選択したファイルのフルパスを返すだけで、自動的には開きません。GetOpenFilenameメソッドの書式は次の通りです。

GetOpenFilename FileFilter, FilterIndex, Title, ButtonText, MultiSelect

引数については、下記で解説します。

表示するファイルの種類を指定する

[ファイルを開く]ダイアログボックスに、どんな種類(拡張子)のファイルを表示するかは、引数FileFilterで指定します。上記のサンプルでは

"Microsoft Excelブック,*.xls?"

と指定しました。もちろん「FileFilter:="Microsoft Excelブック,*.xls?"」と指定しても同じです。両者の違いに関しては、下記のページを参考にしてください。

引数(オプション)名って書かなくていいの?

引数FileFilterには

  • ファイルの種類を表す任意の文字列
  • 表示するファイルの拡張子(ワイルドカード可)

の2つをセットで指定します。

複数の拡張子を表示したいときは、表示したい拡張子をセミコロン(;)で区切ります。

上のように、複数の拡張子をまとめて表示するのではなく、[ファイルの種類]に複数の拡張子を登録するには、登録したい数だけ「任意の文字列,拡張子」のセットを指定します。

引数FileFilterの注意点

  1. 引数全体をダブルコーテーション("")で囲む

    正:"Microsoft Excelブック,*.xls?"

    誤:"Microsoft Excelブック", "*.xls?"

  2. 拡張子しか指定できない

    引数Fileterには拡張子しか指定できません。たとえば

     "Microsoft Excelブック,Book*.xls?"

    のように「Bookで始まる」という意味のワイルドカードを指定しても機能しません。どうしても「○○で始まる」や「○○を含む」ファイル群を表示したいのでしたら、これはもうGetOpenFilenameメソッドではできませんので、下記のページを参考にしてください。

    [ファイルを開く]ダイアログのフィルタリング

キャンセルされたときの処理

[ファイルを開く]ダイアログボックスで、ユーザーが[キャンセル]ボタンをクリックすると、GetOpenFilenameメソッドはFalseを返します。なので、ユーザーが[キャンセル]ボタンをクリックしたかどうかは、次のように判定します。

【受け取る変数が文字列型(String)の場合】

Sub Sample2()
    Dim OpenFileName As String
    OpenFileName = Application.GetOpenFilename("Microsoft Excelブック,*.xls?")
    If OpenFileName <> "False" Then
        Workbooks.Open OpenFileName
    Else
        MsgBox "キャンセルされました"
    End If
End Sub

【受け取る変数がバリアント型(Variant)の場合】

Sub Sample2()
    Dim OpenFileName As Variant
    OpenFileName = Application.GetOpenFilename("Microsoft Excelブック,*.xls?")
    If OpenFileName <> False Then
        Workbooks.Open OpenFileName
    Else
        MsgBox "キャンセルされました"
    End If
End Sub

文字列型(String)で「If OpenFileName <> False」や、バリアント型(Variant)で「If OpenFileName <> "False"」としても判定できますが、これはVBAが内部で自動型変換をしてくれているからです。文字列型は文字列で、バリアント型は論理値で判定するのが、理にかなってます。

何のファイルも選択しないで[開く]ボタンをクリックしても、何も起こりません。なので「[キャンセル]ボタンがクリックされたことと、空白のまま[開く]ボタンがクリックされたこと」を判定する必要はありません。てか、そういう状況は起こりません。

では、もしユーザーが、ファイルを選択するのではなく、[ファイル名]ボックスに任意のファイル名を入力したらどうでしょう。しかも、そのファイル名が間違っていたら・・・

大丈夫です。GetOpenFilenameメソッドが、うまくやってくれます。

ただし、下記で解説するような「複数ファイルが選択可能」なダイアログボックスでは、[キャンセル]ボタンがクリックされたときの判定が異なります。詳しくは下記をご覧ください。

任意のフォルダを開く

GetOpenFilenameメソッドを実行して開いた[ファイルを開く]ダイアログボックスでは、カレントフォルダが表示されます。なので、任意のフォルダを開きたいときは、GetOpenFilenameメソッドを実行する前に、カレントフォルダを移動してやります。次のコードは、CドライブのWorkフォルダを表示します。

Sub Sample3()
    Dim OpenFileName As String
    ChDrive "C"
    ChDir "C:\Work"
    OpenFileName = Application.GetOpenFilename("Microsoft Excelブック,*.xls?")
    If OpenFileName <> "False" Then
        Workbooks.Open OpenFileName
    Else
        MsgBox "キャンセルされました"
    End If
End Sub

ChDriveステートメントは、カレントフォルダを移動するコマンドです。ただし、ドライブを割り当てていない「\\OtherPC\~」のようなUNCには移動できません。ネットワークパスに移動する方法は、下記のページを参考にしてください。

ネットワークドライブにChDriveする

純粋なファイル名とパスを取得する方法

GetOpenFilenameメソッドの返り値は「E:\Work\Book1.xlsx」のようにパス名を含んだファイル名です。これは、そのままファイルを開くときなどには便利ですが、ときにはパスを除いた純粋なファイル名を使いたい場合もありますし、逆にファイル名を除いたパスだけが欲しいときもあります。GetOpenFilenameメソッドが返すフルパスのファイル名から、パスとファイル名を分離する方法を解説します。なお、ここでは「E:\Work\Book1.xlsx」が選択されたものとします。

まず、パスを除いたファイル名(ここでは、Book1.xlsx)を取得するには、どうしたらいいでしょう。簡単です。Dir関数を使えばいいんです。Dir関数は、引数に指定したファイルが存在するとき、そのファイル名を返します。そのとき、パスは含まれません。

Sub Sample4()
    Dim OpenFileName As String, FileName As String
    OpenFileName = Application.GetOpenFilename("Microsoft Excelブック,*.xls?")
    If OpenFileName <> "False" Then
        FileName = Dir(OpenFileName)
        MsgBox FileName
    Else
        MsgBox "キャンセルされました"
    End If
End Sub

さて、フルパス「E:\Work\Book1.xlsx」から「Book1.xlsx」を取得できました。では、パス部分の「E:\Work\」を得るにはどうしたらいいでしょう。こちらも簡単です。「E:\Work\Book1.xlsx」から「Book1.xlsx」を消せばいいんです。任意の文字列から、ある文字を消すには・・・そう、Replace関数ですね。

Sub Sample5()
    Dim OpenFileName As String, FileName As String, Path As String
    OpenFileName = Application.GetOpenFilename("Microsoft Excelブック,*.xls?")
    If OpenFileName <> "False" Then
        FileName = Dir(OpenFileName)
        Path = Replace(OpenFileName, FileName, "")
        MsgBox Path
    Else
        MsgBox "キャンセルされました"
    End If
End Sub

Replace関数の解説

ちなみに、FileSystemObjectを使う手もあります。

Sub Sample6()
    Dim OpenFileName As String, FileName As String, Path As String
    OpenFileName = Application.GetOpenFilename("Microsoft Excelブック,*.xls?")
    If OpenFileName <> "False" Then
        With CreateObject("Scripting.FileSystemObject")
            FileName = .GetFile(OpenFileName).Name
            Path = .GetFile(OpenFileName).ParentFolder
        End With
        MsgBox FileName & vbCrLf & Path
    Else
        MsgBox "キャンセルされました"
    End If
End Sub

FileSystemObjectの解説

複数のファイルを選択可能にする

[ファイルを開く]ダイアログボックスで、複数のファイルを選択するには、引数MultiSelectにTrueを指定します。

Sub Sample7()
    Dim OpenFileName As Variant
    OpenFileName = Application.GetOpenFilename(FileFilter:="Microsoft Excelブック,*.xls?", _
                                       MultiSelect:=True)
    If IsArray(OpenFileName) Then
        ''選択されたファイルへの処理
    Else
        MsgBox "キャンセルされました"
    End If
End Sub

今までは「GetOpenFilename("Microsoft Excelブック,*.xls?")」と書いてきましたが、今度は「GetOpenFilename(FileFilter:="Microsoft Excelブック,*.xls?")」としました。その理由は、下記のページを参考にしてください。

引数(オプション)名って書かなくていいの?

さて、注目すべきは、GetOpenFilenameメソッドの返り値を受け取る変数の型です。複数ファイルを選択可能にしたときは、受け取る変数をバリアント型(Variant)で宣言します。これは、複数ファイルを選択可能にしたGetOpenFilenameメソッドは配列を返すからです。さらに、[キャンセル]ボタンがクリックされたときには、今度は配列ではなくFalseを返します。つまり「配列と論理値(False)」を格納できる変数でないと困ります。だからバリアント型です。

  • ファイルを選択して[開く]ボタンがクリックされたとき → 変数OpenFileNameは配列になる
  • [キャンセル]ボタンがクリックされたとき → 変数OpenFileNameは論理値(False)になる

ということは、変数OpenFileNameが配列だったらファイルが選択されたということで、変数FileSystemObjectが配列でなかったら[キャンセル]ボタンがクリックされたということです。変数OpenFileNameが配列かどうかを判定するには、IsArray関数を使います。

さて、ユーザーがファイルを選択して[開く]ボタンをクリックすると、選択したファイルが配列で返ります。たとえ1つしか選択しなかったとしてもです。配列のデータを個別に取り出すには、For Eachステートメントを使います。もし、選択されたすべてのブックを開くなら、次のようにします。

Sub Sample7()
    Dim OpenFileName As Variant, Target As Variant
    OpenFileName = Application.GetOpenFilename(FileFilter:="Microsoft Excelブック,*.xls?", _
                                               MultiSelect:=True)
    If IsArray(OpenFileName) Then
        For Each Target In OpenFileName
            Workbooks.Open Target
        Next Target
    Else
        MsgBox "キャンセルされました"
    End If
End Sub

For Eachステートメントの制御変数(ここではTarget)は、バリアント型で宣言します。As Workbookとしてはいけませんよ。For Eachに指定した配列OpenFileNameには文字列が入っているのですから。かといって、As Stringもダメです。For Eachの制御変数には、オブジェクト型かバリアント型しか使えないからです。なので、ここはバリアント型です。