wrote :: 2001.12.05

トップページ > Excel > VBA > 講座:ファイルの操作 > 名前を指定してブックを開く


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

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

Sub Sample04()
    Dim OpenFileName As String
    OpenFileName = Application.GetOpenFilename("Microsoft Excelブック,*.xls")
    If OpenFileName <> "False" Then
        Workbooks.Open OpenFileName
    End If
End Sub

ダイアログボックスを開くのはGetOpenFilenameメソッドです。このGetOpenFilenameメソッドを使いこなせると便利なので、少し詳しく解説しましょう。GetOpenFilenameメソッドの書式は次の通りです。

GetOpenFilename (FileFilter, FilterIndex, Title, ButtonText, MultiSelect)

■表示するファイルタイプを指定する

引数FileFilterには、表示するファイルのタイプを指定します。たとえばダイアログボックスで Excelのブックを選択してもらうのなら、最初からExcelのブックだけが表示されると選択しやすいですね。そんなときはFileFilterに「*.xls」を指定します。



引数FileFilterで指定したファイルのタイプは[ファイルを開く]ダイアログボックスの[ファイルの種類]を特定します。FileFilterには「タイプの説明 , タイプ」と2つセットで指定します。Sample04 のように書いた場合は、次のようになります。



2つ以上のタイプを設定する場合は、カンマで区切って続けます。「Microsoft Excel ブック , *.xls , テキストファイル , *.txt」と指定すると、



となります。このとき、引数FileFilter全体を「""」でくくります。

誤:Application.GetOpenFilename("Microsoft Excelブック","*.xls","テキストファイル","*.txt")

正:Application.GetOpenFilename("Microsoft Excelブック,*.xls,テキストファイル,*.txt")

■選択されたファイル名を格納する変数の型

GetOpenFilenameメソッドで表示された[ファイルを開く]ダイアログボックスで、ユーザーが任意のファイルを選択し[開く]ボタンがクリックされると、GetOpenFilenameメソッドはユーザーが選択したファイルのフルパスを返します。通常は、このファイル名を変数に受けて何らかの処理を行います。

返り値は文字列ですから、受け取る変数の型は「文字列型」か「バリアント型」を指定します。どちらの型を使っても違いがないように思われますが、実は[キャンセル]ボタンがクリックされたときの挙動に変化が生じます。

ここ、ややこしいですから、落ち着いて聞いてください。[キャンセル]ボタンがクリックされたときの返り値を変数に受けたとき、その変数が文字列型のときは「Falseという文字列」が変数に格納されます。一方、バリアント型の変数で受けたときは「Falseという」が格納されます。まあ、よく考えれば当たり前のことです。これで何が変わってくるかというと、[キャンセル]ボタンがクリックされたかどうかの判定です。

Dim OpenFileName As Variant
OpenFileName = Application.GetOpenFilename("Microsoft Excelブック,*.xls")
If OpenFileName <> False Then

上記のように、バリアント型の場合は、変数OpenFileNameに「Falseという」が入りますので、変数の中身が「Falseかどうか」で調べられます。さらに、VBAの場合は「Falseという」は「Falseという文字列」でもある…というルールがありますから、次のように判定することも可能です。

Dim OpenFileName As Variant
OpenFileName = Application.GetOpenFilename("Microsoft Excelブック,*.xls")
If OpenFileName <> "False" Then

しかし、返り値を格納する変数が文字列型だった場合、変数には「Falseという文字列だけが入ることになります。したがって、

Dim OpenFileName As String
OpenFileName = Application.GetOpenFilename("Microsoft Excelブック,*.xls")
If OpenFileName <> "False" Then

という判定式は正常に動作しますが、

Dim OpenFileName As String
OpenFileName = Application.GetOpenFilename("Microsoft Excelブック,*.xls")
If OpenFileName <> False Then

ではエラーになってしまうんです。なぜなら、文字列型変数と論理値であるFalseは比較できないからです。

■純粋なファイル名を取得する方法

GetOpenFilenameメソッドの返り値は「C:\My Documents\Book1.xls」のようにパス名を含んだファイル名です。これは、そのままファイルを開くときなどに便利なのですが、ときにはパスを除いた純粋なファイル名を利用したい場合もあります。そんなとき「\」の位置を文字列の後ろから調べて……などと面倒くさい処理は必要ありません。Dir関数を使えばいいんです。Dir関数は引数に指定したファイルが存在すると、そのファイルの純粋なファイル名だけを返します。

Sub Sample05()
    Dim OpenFileName As Variant
    OpenFileName = Application.GetOpenFilename("Microsoft Excelブック,*.xls")
    If OpenFileName <> False Then
        MsgBox "選択したファイルは " & Dir(OpenFileName) & " です", vbInformation
    End If
End Sub



ちなみに「\」の位置を後ろから調べてファイル名を抜き出すには、次のようにします。

Sub Sample05_01()
    Dim OpenFileName As Variant, tmp As String, i As Long
    OpenFileName = Application.GetOpenFilename("Microsoft Excelブック,*.xls")
    If OpenFileName <> False Then
        For i = Len(OpenFileName) To 1 Step -1
            If Mid(OpenFileName, i, 1) = "\" Then
                tmp = Mid(OpenFileName, i + 1, 256)
                Exit For
            End If
        Next i
        MsgBox "選択したファイルは " & tmp & " です", vbInformation
    End If
End Sub
(Exit Forが抜けていました。指摘していただいた しらいし さん、ありがとうございました)
(ついでに追記しておこう。下のようにやる手もありますね)
Sub Sample05_01B()
    Dim OpenFileName As Variant, tmp As String, i As Long
    OpenFileName = Application.GetOpenFilename("Microsoft Excelブック,*.xls")
    If OpenFileName <> False Then
        i = InStrRev(OpenFileName, "\")
        tmp = Mid(OpenFileName, i + 1)
        MsgBox "選択したファイルは " & tmp & " です", vbInformation
    End If
End Sub
(InstrRev関数はExcel 2000で追加されましたので、それより前のバージョンでは使えません)
(ついでに、FileSystemObjectでやる手もかいておこうかな)
Sub Sample05_01C()
    Dim OpenFileName As Variant, i As Long
    OpenFileName = Application.GetOpenFilename("Microsoft Excelブック,*.xls")
    If OpenFileName <> False Then
        With CreateObject("Scripting.FileSystemObject")
            MsgBox "選択したファイルは " & .GetFile(OpenFileName).Name & " です", vbInformation
        End With
    End If
End Sub
(にしても、このページ、2001年に書いたんですね…7年前のことですから、内容を見直した方がいいかな)


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

GetOpenFilenameメソッドを使って複数のファイルを選択させることができます。[ファイルを開く]ダイアログボックスで複数ファイルの選択を可能にするには、GetOpenFilenameメソッドの引数MultiSelectTrueを指定します。



引数FileFilterと引数MultiSelectだけを指定するときには、

OpenFileName = Application.GetOpenFilename("Microsoft Excelブック,*.xls",,,,True)

と書きます。しかし、これではわかりにくいので、

OpenFileName = Application.GetOpenFilename(FileFilter:="Microsoft Excelブック,*.xls",MultiSelect:=True)

と書く方がいいでしょう。このように名前で指定できる引数のことを「名前付き引数」と呼びます。VBAで使われている引数は、ほとんどが「名前付き引数」です。ただし、名前付き引数のFileFilterなどは、自動的に大文字と小文字が調整されないこともあります。全部小文字でfilefilter:=と書いてEnterキーを押しても変化しない場合もありますので慌てないでください。

さて、複数のファイル名を取得するときは、受け取る変数の型を「バリアント型」で宣言します。[ファイルを開く]ダイアログボックスで複数のファイルを選択して[開く]ボタンがクリックされると、それらのファイル名がバリアント型変数に配列として格納されます。

たとえば「D:\」フォルダで「Book1.xls」「Book2.xls」「Book3.xls」の3ファイルを選択し、返り値をバリアント型変数OpenFileNameで受けた場合は、次のように格納されます。

OpenFileName(1) D:\Book1.xls
OpenFileName(2) D:\Book2.xls
OpenFileName(3) D:\Book3.xls

したがって、すべてのファイル名を取り出すには次のようにします。

Sub Sample06()
    Dim OpenFileName As Variant, tmp As String, i As Long
    OpenFileName = Application.GetOpenFilename(FileFilter:="Microsoft Excelブック,*.xls",MultiSelect:=True)
    For i = 1 To UBound(OpenFileName)
        tmp = tmp & OpenFileName(i) & vbCrLf
    Next i
    MsgBox "選択したファイルは " & vbCrLf & tmp & " です", vbInformation
End Sub



UBound関数は配列の要素数を返す関数です。

さて、上記のSample06では[キャンセル]ボタンがクリックされたかどうかを判定していません。実は、複数選択ではここが厄介なのです。

Sub Sample06_02()
    Dim OpenFileName As Variant, tmp As String, i As Long
    OpenFileName = Application.GetOpenFilename(FileFilter:="Microsoft Excelブック,*.xls", MultiSelect:=True)
    If OpenFileName <> False Then
        For i = 1 To UBound(OpenFileName)
            tmp = tmp & OpenFileName(i) & vbCrLf
        Next i
        MsgBox "選択したファイルは " & vbCrLf & tmp & " です", vbInformation
    Else
        MsgBox "キャンセルされました。", vbInformation
    End If
End Sub

なるほど、[キャンセル]ボタンをクリックすると正常に判定できますが、今度は[開く]ボタンをクリックしたときエラーになります。[開く]ボタンをクリックしてファイル名が返ると、バリアント型変数のOpenFileNameは配列になってしまうからです。配列に対して「OpenFileName <> False」と判定することはできません。挙動を整理すると、

・ファイルを選択しないで [キャンセル] ボタンをクリックする→論理値 False が返る→OpenFileName は配列にならない
・ファイルを選択して [開く] ボタンをクリックする→ファイル名が配列として返る→OpenFileName は配列になる

そこで、複数選択の[ファイルを開く]ダイアログボックスでは、[キャンセル]ボタンがクリックされたかどうかを「変数が配列かどうか」で判定します。これには、IsArray関数を使います。

Sub Sample06_03()
    Dim OpenFileName As Variant, tmp As String, i As Long
    OpenFileName = Application.GetOpenFilename(FileFilter:="Microsoft Excelブック,*.xls", MultiSelect:=True)
    If IsArray(OpenFileName) Then
        For i = 1 To UBound(OpenFileName)
            tmp = tmp & OpenFileName(i) & vbCrLf
        Next i
        MsgBox "選択したファイルは " & vbCrLf & tmp & " です", vbInformation
    Else
        MsgBox "キャンセルされました。", vbInformation
    End If
End Sub


[ブックを開く]戻る← | →進む[ブックを閉じる]