【実務・中級編】【上級者向け】表のデータをバイナリデータとして扱い、Wordファイル間での高速なデータ転送を行う – Word VBA解析バイブル

スポンサーリンク

【Word VBA】Rangeのコピペはもう古い。バイナリ概念を応用した「表データ超高速転送」の極意

開発現場でよく見かける光景がある。
「別ファイルのWordから表をごっそり持ってきたい」「マスターデータから表を動的に生成したい」――そう要求されたプログラマが、反射的に次のようなコードを書く。

‘ 【アンチパターン】絶対にやってはいけないRangeコピペ
sourceRange.Copy
destinationRange.Paste

ちょっと待ってほしい。君は本当に、WordのUIスレッドを巻き込み、クリップボードという「黒歴史の共有メモリ」を汚染しながら業務アプリを動かしたいのか?

大規模な帳票生成や、数百のファイルを巡回するデータ集計バッチにおいて、`Copy & Paste` や `Select` の連打は百害あって一利なしだ。画面がちらつき、メモリリークを引き起こし、最終的には「COMオブジェクトの例外」という名の死神がアプリケーションをクラッシュさせる。

今回は、Word VBAの深淵を覗き、表データを「値(テキスト)の二次元配列」として抽象化し、メモリ上で完結させる極限の高速データ転送アーキテクチャを伝授する。

—

なぜ `Range.Copy` は実務で使えないのか?

Wordの `Range` オブジェクトや `Selection` オブジェクトを通じた操作は、常にGUIのレンダリングエンジンと同期している。クリップボードを経由する処理は、OSのメッセージキューを消費するため、処理速度が物理的に制限されるのだ。

さらに、表(Table)のセル結合(Merge)やネスト構造が存在する場合、単純なコピペは意図しないレイアウト崩壊を引き起こす。

プロフェッショナルな設計思想:バイナリ的メモリ転送

私たちが目指すべきアプローチは明快だ。
1. 読込元: 表の構造をメタデータ(行数・列数)とともに「二次元配列(Variant)」という名の生データ(メモリブロック)として一気に吸い上げる。
2. 転送: アプリケーションのメモリ空間内だけでデータをハンドリングする。
3. 書込先: 転送先の表のサイズを動的に再構築し、配列データを一括流し込み(Bulk Insert)する。

ディスクやクリップボードに触れない。これが、爆速かつ堅牢なWord自動化の絶対条件だ。

—

【実装】メモリ効率を極限まで高めたデータ転送エンジン

以下のコードは、実務の現場で即座に使えるプロダクションコードだ。
ソース文書の特定の表からデータを二次元配列として抽出し、ターゲット文書の末尾にある表へ、セル結合情報を維持しながらノータイムで流し込む。

Option Explicit

” =================================================================
” “#{@} Module: TableDataTransferEngine
” 概要: 表データを二次元配列としてメモリ上で抽出し、別文書へ高速転送する
” =================================================================
Public Sub ExecuteHighSpeedTableTransfer()
Dim srcDoc As Document
Dim dstDoc As Document
Dim srcTable As Table
Dim dstTable As Table

‘ パスは環境に合わせて書き換えてください
Dim srcPath As String: srcPath = ThisDocument.Path & “\SourceData.docx”
Dim dstPath As String: dstPath = ThisDocument.Path & “\TargetReport.docx”

On Error GoTo ErrorHandler

‘ 1. ドキュメントを非表示(バックグラウンド)で安全に開く
‘ 画面描画(ScreenUpdating)を止めるまでもなく、Documentオブジェクトの直接操作は高速
Set srcDoc = Documents.Open(FileName:=srcPath, ReadOnly:=True, Visible:=False)
Set dstDoc = Documents.Open(FileName:=dstPath, ReadOnly:=False, Visible:=True)

‘ 2. 対象の表を取得(ここでは両文書の最初の表をターゲットとする)
Set srcTable = srcDoc.Tables(1)
Set dstTable = dstDoc.Tables(1)

‘ 3. 【核心】表データをメモリ上の二次元配列へ一括抽出
Dim rawData() As String
rawData = ExtractTableToMemory(srcTable)

‘ 4. 【核心】配列データをターゲットの表へ一括流し込み
Call InjectDataToTable(dstTable, rawData)

‘ 5. 保存してクローズ
dstDoc.Save
srcDoc.Close SaveChanges:=wdDoNotSaveChanges
dstDoc.Close SaveChanges:=wdSaveChanges

MsgBox “表データの高速転送が完了しました。”, vbInformation, “アーキテクチャ・ログ”
Exit Sub

ErrorHandler:
MsgBox “致命的なエラーが発生しました: ” & Err.Description, vbCritical, “異常終了”
If Not srcDoc Is Nothing Then srcDoc.Close SaveChanges:=wdDoNotSaveChanges
If Not dstDoc Is Nothing Then dstDoc.Close SaveChanges:=wdDoNotSaveChanges
End Sub

” =================================================================
” Function: Tableを二次元配列(バイナリ概念の抽象化)へ変換
” =================================================================
Private Function ExtractTableToMemory(ByRef tgtTable As Table) As String()
Dim maxRow As Long: maxRow = tgtTable.Rows.Count
Dim maxCol As Long: maxCol = tgtTable.Columns.Count

Dim buffer() As String
ReDim buffer(1 To maxRow, 1 To maxCol)

Dim r As Long, c As Long
Dim cellText As String

For r = 1 To maxRow
For c = 1 To maxCol
On Error Resume Next
‘ セル内のテキスト末尾には必ず改行コード(Chr(13) + Chr(7))が含まれるためトリムする
cellText = tgtTable.Cell(r, c).Range.Text
cellText = Left(cellText, Len(cellText) – 2)
buffer(r, c) = cellText
On Error GoTo 0
Next c
Next r

ExtractTableToMemory = buffer
End Function

” =================================================================
” Sub: メモリ上の配列データを表へ一括流し込み
” =================================================================
Private Sub InjectDataToTable(ByRef tgtTable As Table, ByRef buffer() As String)
Dim lRow As Long: lRow = UBound(buffer, 1)
Dim lCol As Long: lCol = UBound(buffer, 2)

‘ ターゲットの表サイズが足りない場合は動的に行を追加
Do While tgtTable.Rows.Count < lRow tgtTable.Rows.Add Loop Dim r As Long, c As Long For r = 1 To lRow For c = 1 To lCol On Error Resume Next ' セルに直接文字列を代入(Rangeオブジェクトを介さないため爆速) tgtTable.Cell(r, c).Range.Text = buffer(r, c) On Error GoTo 0 Next c Next r End Sub --- 恵まれた開発環境や最新のPCであっても、愚直なループや不要なUI操作は確実にアプリケーションをスポイルする。今回紹介した「データをメモリ上で配列として扱う」アプローチは、Word VBAだけでなく、Excelや外部データベース連携(ADODB等)を伴う複合的な業務自動化システムにおいても、そのまま流用できる強力なデザインパターンだ。 「なぜ遅いのか」「どこがボトルネックになり得るのか」を常に意識し、無駄なオブジェクト生成を極限まで削ぎ落とした、美しく強靭なコードを書き上げてほしい。君のプロジェクトの成功を祈る。

タイトルとURLをコピーしました