【エクセルVBA】Workbooks.Openの使い方とエラーの対処法

エクセルVBAで既存のワークブックを開くためには「Workbooks.Open」文を使います。

「Workbooks.Open」文は、単に使うだけなら簡単な一方で、何も考えずに使ってしまうと、次のようなエラーが発生しがちです。

  • ファイルが存在していないためエラーになる
  • 同一ファイルを既に開いていると、「abc.xlsxは既に開いています。2重に開くと、これまでの変更内容は破棄されます。abc.xlsxを開きますか?」というメッセージが出てしまう
  • 同一名称の別ファイルを開いているため、正常に動作しない

そこで、このページでは「Workbooks.Open」文の使い方と、これらのトラブルの対処法を解説していきます。


1. Workbooks.Open文の基本

Workbooks.Openは、次のように使います。

基本的な使用例

Sub OpenWorkbookTest()
  Dim Filepath
  Filepath = "C:¥temp¥test1.xlsx"

  Dim targetWorkbook As Workbook
  Set targetWorkbook = Workbooks.Open(Filepath)

' 対象ブックの   「Sheet1」シートの    「A1」セルの  値
  targetWorkbook.Worksheets("Sheet1").Cells(1, 1).Value = "テスト書き込み"
End Sub

3行目で、開きたいブックのファイルパスを、変数「Filepath」に代入しています。

以下、変数「Filepath」を使って処理を書いていきます。

実際に、このプログラムを使うときは、3行目の「C:¥temp¥test1.xlsx」の部分を、エクセルブックのファイルパスに書き換えてください。

変数宣言+Workbooks.Openでブックを開く

5行目~6行目で、エクセルブックを開いています。

  Dim targetWorkbook As Workbook
  Set targetWorkbook = Workbooks.Open("C:¥temp¥test1.xlsx")

5行目で「ワークブックを操作」するための変数「targetWorkbook」を宣言しています。

6行目で「Workbooks.Open」文を使って、変数「Filepath」(=「C:¥temp¥test1.xlsx」)にあるエクセルブックを開いています。

そして、その「開いたエクセルブック」の情報を変数「targetWorkbook」に代入しています。

以降、「targetWorkbook」という変数を通じて、そのワークブックを操作することができます。

「Workbooks.Open」という文を、よく見ると「Workbooks.Open」というように「s」が付いていることに注意してください。

イメージ的には、《複数のWorkbookの管理をする「Workbooksオブジェクト」》に対して、新しいWorkbookを「Open」するように依頼する、と考えてみてください。

変数「targetWorkbook」を使って、ワークブックを操作する

' 対象ブックの   「Sheet1」シートの    「A1」セルの  値
  targetWorkbook.Worksheets("Sheet1").Cells(1, 1).Value = "テスト書き込み"

このように、9行目で、

  • 対象ワークブックの
  • 「Sheet1」シートの
  • 「A1」セルの「値」に
  • 「テスト書き込み」という文字を

書き込んでいます。

2. Workbooks.Openでエラーが出る

このように「Workbooks.Open」文を使うだけなら、簡単です。

ただ、状況によっては様々なエラーが出るなど、うまく動かないケースもあります。

そこで、ここからは、Workbooks.Openでありがちなエラーなどの対処法を紹介していきます。

パターン1. 該当するファイルが存在しない

該当するファイルがないと「Workbooks.Open」はうまく動かず、エラーになってしまいます。

そこで「Workbooks.Open」を使う前に、ファイルが存在しているかチェックをかけましょう。

ファイルの存在チェックを追加

Sub OpenWorkbookTest_CheckBeforeOpen()
  Dim Filepath
  Filepath = "C:¥temp¥testNotExists.xlsx"

  If Dir(Filepath) = "" Then
    MsgBox "指定したファイルは存在していません"
    Exit Sub
  End If
  
  Dim targetWorkbook As Workbook
  Set targetWorkbook = Workbooks.Open(Filepath)

' 対象ブックの   「Sheet1」シートの    「A1」セルの  値
  targetWorkbook.Worksheets("Sheet1").Cells(1, 1).Value = "テスト書き込み"
End Sub

さきほどのプログラムに、5行目~8行目の部分を追加しています。

Dir関数でファイルが存在しているかどうかを確認する

  If Dir(Filepath) = "" Then
    MsgBox "指定したファイルは存在していません"
    Exit Sub
  End If

ファイルが存在していないときには、Dir関数を使った結果が空欄になります。

そこでIf文を使って、ファイルが存在するかどうか確認を行い、ファイルがないときには、Msgboxでその旨を表示してプログラムの実行を中止します

逆に、ファイルがあれば、10行目以降で実際にブックを開いて処理を行います(先ほどとまったく同じです)。

Dir関数の詳細

「Dir(Filepath)」という文は、次のような動作をします。

状況 結果
ファイルが「ない」とき (空欄)
ファイルが「ある」とき Filepathの内容がそのまま得られる

たとえば、

  • 「C:¥temp¥testNotExists.xlsx」は存在しない
  • 「C:¥temp¥test1.xlsx」は存在している

というときに、イミディエイトウィンドウでDir関数を実行すると、次のようになります。

パターン2. 既に同じ「名前」のエクセルブックを開いている

エクセルの仕様で、既に同じ「名前」のエクセルブックを開いているときには、別のエクセルブックを開くことはできません

そのため「Workbooks.Open」文を実行する前に、同名のエクセルブックを開いていないかを確認します。

「同名のエクセルブックが開けない」という制約は、ファイルパスは無関係に、ファイル名が同一かどうかだけで判定されます

たとえば、下記のエクセルブックは、ファイルパスは違いますが、ファイル名が同一のため、すべて「同名」だと判定されます。

  • 「C:¥test1.xlsx
  • 「C:¥temp¥test1.xlsx
  • 「D:¥temp¥test1.xlsx

要は「test1.xlsx」の部分が同じなら、すべて「同じ名前」と判断されてしまうということです。

 

それでは、具体的なプログラムを見ていきます。

同名のファイルを開いていないかのチェックを追加

Sub OpenWorkbookTest_CheckBeforeOpen2()
  Dim Filepath
  Filepath = "C:¥temp¥test1.xlsx"

  If Dir(Filepath) = "" Then
    MsgBox "指定したファイルは存在していません"
    Exit Sub
  End If
  
  Dim FSO As Object
  Set FSO = CreateObject("Scripting.FileSystemObject")
  
  Dim Filename
  Filename = FSO.GetFileName(Filepath)
  
  'filenameと同名のエクセルブックを取得
  Dim workbookWithSameName As Workbook
  Set workbookWithSameName = getWorkbookByName(Filename)
 
  '同名のエクセルブックがあるときはNothing「ではない」
  If Not workbookWithSameName Is Nothing Then
    MsgBox "同名のエクセルブックを開いているためファイルを開けません"
    Exit Sub
  End If
    
  Dim targetWorkbook As Workbook
  Set targetWorkbook = Workbooks.Open(Filepath)
  
'   対象ブックの   「Sheet1」シートの    「A1」セルの  値
  targetWorkbook.Worksheets("Sheet1").Cells(1, 1).Value = "テスト書き込み"
End Sub


'以下は、https://www.excelspeedup.com/getworkbook/ からコピペ
Function getWorkbookByName(targetWorkbookName) As Workbook
  Dim TempWorkbook As Workbook
  For Each TempWorkbook In Workbooks
    If TempWorkbook.Name = targetWorkbookName Then
      Set getWorkbookByName = TempWorkbook
      Exit Function
    End If
  Next
  
  Set getWorkbookByName = Nothing
End Function

さきほどのプログラムに対して、10行目~24行目と34行目~を追加しています。
かなり、プログラムが長くなってしまいましたが、解説をしていきます。

ファイルパスからファイル名を取得

10行目~14行目では「ファイルパス」から「ファイル名」を抽出しています。
(例:「C:¥temp¥test1.xlsx」→「test1.xlsx」)

この抽出をするために「FilesystemObjectオブジェクト」の「GetFileNameメソッド」を使います。

  Dim FSO As Object
  Set FSO = CreateObject("Scripting.FileSystemObject")
  
  Dim Filename
  Filename = FSO.GetFileName(Filepath)
10行目~11行目

FileSystemObjectを使える状態にしたものを、変数FSOに格納

13行目~14行目

変数FSO(=FileSystemObjectを使える状態にしたもの)の「GetFileNameメソッド」を呼び出し。

その結果、「変数Filepath」のファイルパスを変換して、ファイル名を「変数Filename」に代入。

これで、ファイルパスからファイル名を取得できました。

ファイル名と同名のワークブックを開いていないかを調べる

  'filenameと同名のエクセルブックを取得
  Dim workbookWithSameName As Workbook
  Set workbookWithSameName = getWorkbookByName(Filename)

すでに、同名のワークブックを開いていないかを調べます。

18行目のgetWorkbookByNameプロシージャを実行すると、変数workbookWithSameNameには、次の値が代入されます。

同名のワークブックがある場合 該当するワークブックを操作するための情報
同名のワークブックがない場合 Nothing

つまり、「変数workbookWithSameName」がNothingかどうかを判定すれば、同名のワークブックがあるかどうかがわかるのです。

18行目にある「getWorkbookByName(Filename)」で、34行目~45行目のFunctionプロシージャを呼び出しています。

そして、そのFunctionプロシージャの中で、同名のワークブックがないか検索する処理を行っています。

このFunctionプロシージャの具体的な動作は、下記ページで解説していますので、合わせてご覧ください。

同名のワークブックを開いているかどうかの判定

「変数workbookWithSameName」がNothingではない場合には、同名のエクセルブックを開いている状態だということがわかります。

そこで、If文を使って判定をします。

  '同名のエクセルブックがあるときはNothing「ではない」
  If Not workbookWithSameName Is Nothing Then
    MsgBox "同名のエクセルブックを開いているためファイルを開けません"
    Exit Sub
  End If

21行目のIf文は「Not ... Is Nothing」と否定が2回入っているので読みにくいかもしれませんが、これで「Nothingではない」という条件を表しています。

「変数workbookWithSameName」がNothingでないとき

「Nothingではない」=「同名のエクセルブックを開いている」ということです。

この条件が成り立つときは、同名のエクセルブックを開いている旨メッセージを出して、プログラムの実行を終了します。

「変数workbookWithSameName」がNothingのとき

「Nothing」=「同名のエクセルブックを開いていない」ということです。

この場合は、「Workbooks.Open」をしてもエラーが出ないはずですから、今まで通り「Workbooks.Open」の処理を行っていきます。

これで、同名のワークブックを開いている場合には、処理を中断されるようになりました。

パターン3. 同一エクセルブックを開いているときは処理を継続したい

パターン2では「同名のエクセルブックを開いている」ときに、処理を中断しました。

でも、同名の中でも、処理をしようとしていたエクセルブックそのものを開こうとしているときは、処理を継続できたほうが便利そうです

たとえば、「C:¥temp¥test1.xlsx」というエクセルブックを開きたいと思ったときには、次のような処理ができれば理想的です。

C:¥test1.xlsx」 × 別ファイルなので中断
C:¥temp¥test1.xlsx」  開きたいエクセルブックそのものなので処理を継続
D:¥temp¥test1.xlsx」 × 別ファイルなので中断

そこで、このような判断をするロジックを追加します。

処理対象ブックを既に開いているときは処理を継続する

Sub OpenWorkbookTest_CheckBeforeOpen3()
  Dim Filepath
  Filepath = "C:¥temp¥test1.xlsx"

  If Dir(Filepath) = "" Then
    MsgBox "指定したファイルは存在していません"
    Exit Sub
  End If
  
  Dim FSO As Object
  Set FSO = CreateObject("Scripting.FileSystemObject")
  
  Dim Filename
  Filename = FSO.GetFileName(Filepath)
  
  'filenameと同名のエクセルブックを取得
  Dim workbookWithSameName As Workbook
  Set workbookWithSameName = getWorkbookByName(Filename)
 
  '同名のエクセルブックがあるときはNothing「ではない」
  If Not workbookWithSameName Is Nothing Then
    If workbookWithSameName.FullName <> Filepath Then
      MsgBox "同名のエクセルブックを開いているためファイルを開けません"
      Exit Sub
    End If
  End If
   
  Dim targetWorkbook As Workbook 

  If workbookWithSameName Is Nothing Then
    Set targetWorkbook = Workbooks.Open(Filepath)
  Else
    Set targetWorkbook = workbookWithSameName
  End If
  
'   対象ブックの   「Sheet1」シートの    「A1」セルの  値
  targetWorkbook.Worksheets("Sheet1").Cells(1, 1).Value = "テスト書き込み"
End Sub


'以下は、https://www.excelspeedup.com/getworkbook/ からコピペ
Function getWorkbookByName(targetWorkbookName) As Workbook
  Dim TempWorkbook As Workbook
  For Each TempWorkbook In Workbooks
    If TempWorkbook.Name = targetWorkbookName Then
      Set getWorkbookByName = TempWorkbook
      Exit Function
    End If
  Next
  
  Set getWorkbookByName = Nothing
End Function

先ほどのプログラムに22行目、25行目、30行目、32行目~34行目を付け加えています。

WorkbookオブジェクトのFullNameプロパティでワークブックのファイルパスを取得

    If workbookWithSameName.FullName <> Filepath Then
      MsgBox "同名のエクセルブックを開いているためファイルを開けません"
      Exit Sub
    End If

22行目で、次の2つの比較をしています。

workbookWithSameName.FullName 既に開いている同名ワークブックの「ファイルパス」
Filepath 開きたいワークブックの「ファイルパス」

そして、一致していないときだけ23~24行目のロジックを実行(=処理を中断)します。

対象ブックを既に開いているときは、そのブックを処理対象とする

  If workbookWithSameName Is Nothing Then
    Set targetWorkbook = Workbooks.Open(Filepath)
  Else
    Set targetWorkbook = workbookWithSameName
  End If
変数「workbookWithSameName」がNothingのとき

同名のワークブックを開いていない状態なので、新しくワークブックを「Open」する処理を行います。

変数「workbookWithSameName」がNothingではないとき

変数「workbookWithSameName」に「既に開いているブック」の情報が格納されています。

そこで、Workbooks.Openをする代わりに33行目で、その情報を「targetWorkbook」にコピーします。

既に、同一ファイルを開いているときに「Workbooks.Open」を行わないのが、このプログラムのポイントです。

同一ファイルを既に開いている状態で、Workbooks.Openをしてしまうと、「test1.xlsxは既に開いています。2重に開くと、これまでの変更内容は破棄されます。test1.xlsxを開きますか?」というメッセージが表示される場合があります。

 

実際に、このマクロを動かしたときの様子です↓

※下記を再生しても音は出ませんので、音が出せない環境でもご安心ください。

3. まとめ

Workbooks.Open文は、そのまま使うと、次のような場合にエラーが発生します。

  • 指定したファイルが存在していない
  • 既に同名のファイルを開いている

適切な事前チェックをすれば、このような原因でのエラーを防ぐことができます。

面倒ですが、必要に応じて事前チェックを入れて、適切な対策を取りましょう。

エクセル基礎講座 「無料」動画マニュアル

「経理事務のためのエクセル基礎講座(初級編)」(動画マニュアル 総収録時間162分)を無料プレゼント中です!

このマニュアルで解説していることを一通り学べば、経理事務を行う上で最低限必要となる知識が得られます。

ご登録者の方には、合わせて、公認会計士が実体験を通して身に付けたエクセルを使う技をメールにてお伝えしていきます!

無料動画講座 登録フォーム

※ご登録頂いたメールアドレスに、エクセルを使いこなすための情報を配信するメールセミナー「エクセル倍速講座」も合わせて配信させていただきます。