VBA【最速】開かずに別ブックから【値を取得】セルの転記【自由度MAX】

最速かつ自由に柔軟にVBAで他のエクセルブックからセルの値を取得し
指定範囲のデータを抽出する方法を紹介します。

結論を申しますと
別ブックから転記など、値を読み出す処理をする場合は
今回、紹介する方法が一番、処理速度が速く、汎用性があるので色々な効率が良いです。

別ブックのセルの値を取得するのは、覚えてしまえば簡単です。

別のブックを裏で開くことにより、開かずに取得しているような感じで別ブックの値を取得できます。

表示処理をしていないので、処理速度もかなり向上しています。
ですので、別のブックからの値を複数取得したい時にも、高速で使用可能です。

また、別のブックから値を参照し
色んな値をループして取得したい時にも問題なく使えます。

なので、別ブックの値を開かずに値を取得したい方には、オススメです。

値を取得するだけではなく、開かずに値を書き込む事も可能です。

もちろん単純な「Workbooks.Open」という初級レベルではありません。

単純な「Workbooks.Open」だと、処理速度が遅いですよね。

VBAの処理は少しでも速い方が良いので
VBAが遅くなる原因になりかねない単純な「Workbooks.Open」は、使用を控えましょう。

あと有名なのは「ExecuteExcel4Macro」もあります。

別のブックを開かずに値を取得できます。
ですが、他のブックからセルの値を取得するのに制約が多く、柔軟性に欠けます。

エクセルで色々作っていると他のファイルからデータを抽出したいですよね。

「ExecuteExcel4Macro」は、昔のマクロのコードなので使用するのは避けましょう。

Excelの関数で別ブックの値を取得しようとすると
少しファイル名が変わると、うまくいかないし、「INDIRECT」関数だと限界がありますよね。

では、VBAで別のブックのセルから値を取得する、最速な方法を説明します。

別のブックからデータを抽出する方法がいくつかありますが
今回、紹介する方法を覚えておくと、なにかと便利ですよ。

注意事項もあるので、必ず目を通してください。

VBA高速化に興味ある方は、こちらをご覧ください。

◆最速で他のブックを開く方法

サンプルコード

Sub 最速で別ブックを開く()
Dim ExcelApp As New Application
Dim Wb As Workbook
Dim ReadFolderFullPath  As String

'開くExcelファイルを指定
ReadFolderFullPath = ThisWorkbook.Path & "\" & "Book1.xlsx"

'エクセルを不可視で開く
ExcelApp.Visible = False      'エクセル可視/不可視設定
ExcelApp.DisplayAlerts = False      '警告メッセージをオフ
Set Wb = ExcelApp.Workbooks.Open(ReadFolderFullPath, , True)    '読取り専用で開く

'処理例
'別ブックのセルの値を取得
Debug.Print Wb.Worksheets("Sheet1").[A1].Value

ExcelApp.DisplayAlerts = True      '警告メッセージをオン
ExcelApp.Quit      'Excel終了
Set ExcelApp = Nothing      '参照を解放
End Sub

解説

あれほど、「Workbooks.Open」をバカにしましたが、使っています(笑)

ですが、単純ではありません。

マクロを実行しているエクセルとは、違う新しいアプリケーションでエクセル(変数:ExcelApp)を開くいています。

そうすると、不可視設定ができますので、表示する処理時間を省く事により
VBA高速化に繋がります。

処理的にはブックを開いていますが
見た目上は非表示なので、別ブックのファイルを開かずにセルの値を取得しているような
感じになります。

VBAでファイルを開かずに値を取得する方法として一番オススメです。

無駄な表示処理をなくす事により、速い処理で他のブックの値を読みだす事ができます。

柔軟で高速に別ブックのセルの値を取得するのは、この方法です。

VBAコードの中身を順に説明します。

理解した後は、下部の注意事項を必ず目を通してください。

・「Dim ExcelApp As New Application」

別のアプリケーションのエクセル用のオブジェクト変数です。

この変数を使用するには、「ツール」→「参照設定」から
「Microsoft Scripting Runtime」を探し出し、チェックを入れてください。

※↑何か勘違いしていたみたいで、チェックはなくても問題なく動きそうでした。

・変数:「ReadFolderFullPath」

「ReadFolderFullPath」という変数には、開くエクセルのパスとファイル名(拡張子まで)を代入してください。

・「ExcelApp.Visible = False」

「ExcelApp.Visible = False」でブックを開く前に不可視の設定にしています。

「True」にすれば、可視できるようになるので
デバッグ時は、「True」の方が便利かもしれませんね。

・「Set Wb」

「Set Wb = ExcelApp.Workbooks.Open(ReadFolderFullPath, , True) 」の文についてです。

他のブックを開くと同時に、変数「Wb」に開いた他のエクセルブックがオブジェクトとして格納されます。

「True」の所を「False」にすると、読取り専用ではなく、通常に開きます。

データの書き換えをする場合は、「False」にしてくださいね。

別ブックは不可視なので色々、気を付けてください。

・他のブックの値を取得

Debug.Print Wb.Worksheets("Sheet1").[A1].Value

上記のサンプルコードで別ブックのセルの値を取得する事ができます。

セルの値を取得する方法は、別のエクセルブックオブジェクトを指定して、後は、通常通りですね。

VBAって「[A1]」でセルの指定できるの?って疑問に思いますよね。

気になりますよね。

こちらの記事で紹介していますのでご覧ください。

・「ExcelApp.Quit」

「ExcelApp」を終了します。

必ず、「ExcelApp.Quit」は実行してください。

要は、エクセルを閉じる事と同じで、右上の「×」ボタンと同じです。

デバッグ時に「ExcelApp.Quit」を実行せずに、途中終了すると
「ExcelApp」が不可視で開かれた状態で残ります。

要は、裏で開きっぱなしです。

タスクマネージャーから終了する、又は、PCを再起動しないと閉じることはできません。

「ExcelApp」の変数を理解していない方に言いますが
「ExcelApp.Quit」では、VBAを実行しているブックは閉じませんので安心してください。

不安なら「ThisWorkbook.Save」でも入れといてください。

当然、保存する処理時間は遅くなりますので、非推奨ですが。

・「Set ExcelApp = Nothing」

いわゆる、おまじないですね。

「ExcelApp」によって占有しているPCメモリ(わずか)を解放します。

「ExcelApp」はPublic変数ではないので、プロシージャ(1つのマクロ)が終了すれば
解放される変数なので
個人的にはいらないと思いつつも、おまじないとして、入れています。

◆注意事項

・開いたら閉じる

物を出したら片づけますよね。

アプリも開いて、使い終わったら閉じますよね。

それと同じで、見えないように別のブックを開いたからと言って、閉じないのはやめましょう。

デバッグ時やエラー時にVBAを強制途中終了する前に、必ず、「ExcelApp.Quit」を実行してください。

・不可視にしている事を理解する

「ExcelApp.Visible = False」によって、不可視にしているので

ファイル名を間違えたり
不可視のエクセルファイルを書き込みしようとして、セルアドレスを間違えたりしないようにしてください。

ただでさえ、別のブックをバックグラウンドで開いているので、気づかない可能性もありますので
お気を付けください。

最初のうちは、バックアップを取ることをオススメします。

◆応用編

・別のブックから転記する方法

別のブックから一定の範囲を高速に転記する方法を紹介します。

特にこれと言って難しくないんですが、サンプルコードを記載します。

サンプルコード

Sub 最速で別ブックから転記()
'「Microsoft Scripting Runtime」にチェック(「ツール」→「参照設定」(Alt→T→R))
Dim ExcelApp As New Application
Dim Wb As Workbook
Dim ReadFolderFullPath  As String

'開くExcelファイルを指定
ReadFolderFullPath = ThisWorkbook.Path & "\" & "Book1.xlsm"

'エクセルを不可視で開く
ExcelApp.Visible = False      'エクセル可視/不可視設定
ExcelApp.DisplayAlerts = False      '警告メッセージをオフ
Set Wb = ExcelApp.Workbooks.Open(ReadFolderFullPath, , True)    '読取り専用で開く


'------------------------------------------
'↑ここまでは上記サンプルコードと同一↑

'転記処理
With Wb.Worksheets("Sheet1")
     Worksheets("Sheet1").[A1:B10].Value = .[A1:B10].Value
End With


'↓ここから下は上記サンプルコードと同一↓
'------------------------------------------

ExcelApp.DisplayAlerts = True      '警告メッセージをオン
ExcelApp.Quit      'Excel終了
Set ExcelApp = Nothing      '参照を解放
End Sub

解説

VBAで別のブックのセルから値を取得する高速な方法は、配列を使う事です。

「Worksheets(“Sheet1”).[A1:B10].Value = .[A1:B10].Value」のセル範囲を変えれば
色んな範囲を転記する事が出来ます。

リンク:[A1:B10]でセルを楽に指定する方法

セルの範囲指定をしていますが、セルも配列の一種です。

配列変数を使用すれば、もっと様々な範囲を高速に転記することができると思います。

配列変数について詳しく記載した記事はこちらになります。

・別ブックの最終行を取得する方法

別のブックのA列最終行を取得する方法を紹介します。

こちらも難しくないのですが、サンプルコードを記載します。

サンプルコード

Sub 別ブックの最終行を取得()
'「Microsoft Scripting Runtime」にチェック(「ツール」→「参照設定」(Alt→T→R))
Dim ExcelApp As New Application
Dim Wb As Workbook
Dim ReadFolderFullPath  As String

'開くExcelファイルを指定
ReadFolderFullPath = ThisWorkbook.Path & "\" & "Book1.xlsm"

'エクセルを不可視で開く
ExcelApp.Visible = False      'エクセル可視/不可視設定
ExcelApp.DisplayAlerts = False      '警告メッセージをオフ
Set Wb = ExcelApp.Workbooks.Open(ReadFolderFullPath, , True)    '読取り専用で開く


'------------------------------------------
'↑ここまでは上記サンプルコードと同一↑


'◆最終行取得処理◆

Dim StartRow As Long, LastRow_1 As Long _
    , LastRow_2 As Long
    
With Wb.Worksheets("Sheet1")
'###---処理A---###
'●確実に最終行を取得
    For StartRow = 1 To 100000
        If .Cells(StartRow, 1) = "" Then
            LastRow_1 = StartRow - 1
            Exit For
        End If
    Next StartRow
'###------------###

'###---処理B---###
'●簡易的な最終空白行を取得
    '関数入力セル等があると正常に最終行取得できない
    LastRow_2 = Range("A1").End(xlDown).Row '入力がある最終行
End With
'###------------###

'LastRow_1  :確実に最終行を取得する方法で、こちらが推奨です
'LastRow_2  :簡易的な最終空白行を取得する方法で
'           :関数入力セル等があると正常に最終行取得できません

'↓ここから下は上記サンプルコードと同一↓
'------------------------------------------

ExcelApp.DisplayAlerts = True      '警告メッセージをオン
ExcelApp.Quit      'Excel終了
Set ExcelApp = Nothing      '参照を解放

End Sub

解説

サンプルコードの処理Aか処理Bを削除して、ご使用ください。

処理Aを残して、処理Bを削除するのがオススメです。

こちらを参考にしていますので、下記の記事をご覧ください。

◆よくあるVBAで他のブックのセルの値を取得する方法

・単純な「Workbooks.Open」

これはシンプルに遅いです。

別のブックを開くのが1個なら、気にならないかもしれませんが
どうせなら、今回紹介した、VBAで「最速で他のブックを開く方法」を覚えてください。

・「ExecuteExcel4Macro」

セル1個など限定的な条件では
今回紹介した方法より、速いかもしれません。

ですが、複数はできないなど、使える条件が厳しすぎます。

シート名が固定されていないとダメだったり、取得するセル数が決まっている等
色々ななんじゃこりゃというような制約がありますので、オススメはできません。

少し違う事にしようとした時に、嫌な気持ちになると思います。

実際、私がそうでした(笑)。

「ExecuteExcel4Macro」でコード書くと
後々、おすすめの別のブックから値を取得するサンプルコードにしておけばよかったと
後悔すると思います。

◆この記事をご覧になった方へのおすすめリンク

マクロを高速化したいあなたへ~VBA高速化の常識~


マクロでできることをおさらい

◆まとめ

他のブックのセルの値を取得するのに、単純な「Workbooks.Open」は通常の使い方をしないで
新しいエクセルオブジェクトから他のブックを開いて、セルの値を取得しましょう。

そうすると、以前とは比べ物にならないくらい、別ブックのセルの値取得が速くなります。

“VBA【最速】開かずに別ブックから【値を取得】セルの転記【自由度MAX】” への6件の返信

  1. いつもFor文でセル入力してましたがEvaluateつかった配列の速度グロいですね!
    For文と比べたら速度10分の1くらいでした!
    もはや応用編がメイン・・・w

    ExcelApp使ったOpenメソッドの利用なのですが
    使い方が悪いせいか逆に遅くなりました。
    普通に開いて
    Application.ScreenUpdatingとDisplayAlertsをFalseに
    切り替えるので十分かなと思います。

    1. 「Evaluate」を使わなくても「Range」でも「Cells」でも速度は、ほとんど変わりませんよ。
      「配列」を使うことが大幅なVBAの処理速度を速くしています。
      「Evaluate」に関しては、こちらをご覧ください。
      https://jovba.com/2022/03/27/vba-cell_specify/#k1
      「配列」に関しては、こちらをご覧ください。
      https://jovba.com/2022/02/17/ary1/
       
      —————————————————-
       
      >ExcelApp使ったOpenメソッドの利用なのですが
      >使い方が悪いせいか逆に遅くなりました。
      とのことですが
      「ExcelApp.Visible = False」
      で、表示をしていないので、少なくとも数秒は処理は速くなるはずです。
      1つだけではなく、別のエクセルを複数開けば開くほど、VBAの処理が速くなることを実感できると思います。
      なので、他の処理が悪さしている可能性があります。
      再計算の設定などは問題ないでしょうか。
      詳細はこちらをご覧ください。
      https://jovba.com/2022/02/14/macro_speed/

  2. お問い合わせフォームから
    思い通りにいかないコードを送り、確認してもらいました。
    その後、修正して頂きましてありがとうございました。
    確かに自分の思い描いていた挙動になっていました。
    ご対応頂きありがとうございました。

    1. 思い描いていた挙動になってよかったです。
      修正した箇所と修正した方がいい箇所を記載したので
      しっかり確認して、今後の参考にしてください。

  3. この方法において、最終行の行番号を取得する方法を教えてください

    1. 別ブックの最終行の取得については、こちらの記事の応用で可能です。
      VBA【最終行取得】を確実にする方法

      下記の処理Aか処理Bを削除して、ご使用ください。
      処理Aを残して、処理Bを削除するのがオススメです。
      違いが理解できるのなら、ご自分で判断してご使用ください。
      詳しくは上記、記事をご覧ください。
      ‘———————-
      ‘///
      ‘//別のブックを開くコードは、省きます//
      ‘///
      ‘処理例
      ‘別ブックA列最終行の行番号を取得する方法
      Dim StartRow As Long, LastRow_1 As Long _
      , LastRow_2 As Long

      With Wb.Worksheets(“Sheet1”)
      ‘###—処理A—###
      ‘●確実に最終行を取得
      For StartRow = 1 To 100000
      If .Cells(StartRow, 1) = “” Then
      LastRow_1 = StartRow – 1
      Exit For
      End If
      Next StartRow
      ‘###————###

      ‘###—処理B—###
      ‘●簡易的な最終空白行を取得
      ‘関数入力セル等があると正常に最終行取得できない
      LastRow_2 = Range(“A1”).End(xlDown).Row ‘入力がある最終行
      End With
      ‘###————###

      ‘LastRow_1 :確実に最終行を取得する方法で、こちらが推奨です
      ‘LastRow_2 :簡易的な最終空白行を取得する方法で
      ‘ :関数入力セル等があると正常に最終行取得できません

      ‘———————-

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です