VBScriptでバイナリを制する:ADODB.Streamによる高精度ファイルパースの極意
VBScriptを単なる「簡易的なバッチツール」だと思っているなら、それは大きな勘違いだ。WSH環境下において、`ADODB.Stream`を自在に操るスキルは、現代のRPAツールや複雑なワークフローを支える「最後の砦」となり得る。
今日は、テキスト処理の範疇を超え、画像やZIPといったバイナリデータの深淵に触れるための「堅牢なバイナリパース」の設計指針を授ける。
—
1. なぜ「ADODB.Stream」一択なのか?
バイナリを扱う際、初心者はしばしば `Scripting.FileSystemObject` の `OpenTextFile` に手を出すが、これは致命的な間違いだ。FSOはテキスト処理用であり、マルチバイト文字やバイナリのNullコードに遭遇した瞬間にストリームが崩壊する。
対して `ADODB.Stream` は、Windows OSの根幹に近いバイナリデータ処理ユニットだ。`Type = 1 (adTypeBinary)` を指定することで、OSレベルのバッファを直接メモリに展開できる。この「生」のバイト列を扱うことが、バグを排除するための第一歩となる。
—
2. 堅牢なバイナリ読み込みの設計原則
バイナリ操作には、以下の3つの鉄則がある。
1. Readは一括で行わない: 数百MBのファイルを読み込むとメモリがパンクする。ヘッダー(マジックナンバー)だけを読み取る場合は、必ず必要バイト数だけを切り出すこと。
2. 型変換を信じるな: VBScriptはVariant型に依存している。バイト列を扱うときは `AscB` や `MidB` を使い、文字列操作用関数(`Asc`, `Mid`)は厳禁とする。
3. ストリームのライフサイクル管理: `Close`を怠るな。巨大なバイナリを扱う場合、ガベージコレクションを待つ余裕など現場にはない。
—
3. 実装:バイナリパース・プロダクションコード
以下に、バイナリファイルのヘッダー情報を読み取り、16進数(Hex)としてダンプする実務用コードを提示する。
‘ ———————————————————
‘ バイナリ解析ユーティリティ: ファイルの先頭Nバイトを16進数で抽出
‘ ———————————————————
Option Explicit
Function GetBinaryHeader(filePath, length)
Dim adoStream, binData, i, hexStr
‘ ADODB.Streamオブジェクトの生成
Set adoStream = CreateObject(“ADODB.Stream”)
On Error Resume Next
adoStream.Type = 1 ‘ adTypeBinary
adoStream.Open
adoStream.LoadFromFile filePath
If Err.Number <> 0 Then
GetBinaryHeader = “Error: File Open Failed”
Exit Function
End If
On Error Goto 0
‘ 指定バイト数だけ読み込み
binData = adoStream.Read(length)
adoStream.Close
Set adoStream = Nothing
‘ バイト列を16進数文字列へパース
hexStr = “”
For i = 1 To LenB(binData)
‘ AscBで1バイト取得し、2桁の16進数に変換
hexStr = hexStr & Right(“0″ & Hex(AscB(MidB(binData, i, 1))), 2) & ” ”
Next
GetBinaryHeader = Trim(hexStr)
End Function
‘ 使用例: デスクトップのtest.zipの先頭4バイトを解析
Dim filePath, headerInfo
filePath = CreateObject(“WScript.Shell”).SpecialFolders(“Desktop”) & “\test.zip”
headerInfo = GetBinaryHeader(filePath, 4)
WScript.Echo “Header Signature: ” & headerInfo
‘ ZIPファイルなら 50 4B 03 04 が表示されるはずだ
—
4. プロの眼:コードの解説と注意点
MidB と AscB の不可欠性
VBScriptの通常の `Mid` 関数は、Unicode文字を基準に動作する。バイナリデータは「文字」ではないため、これを使うとデータが文字コード変換(Shift-JIS/UTF-8)の影響を受け、破壊される。バイナリには必ず「B」がつく関数を使うこと。 これを忘れる者はエンジニア失格だ。
パフォーマンスの最適化
もし数千個のファイルを連続処理する場合、`CreateObject` をループ内で呼ぶのはオーバーヘッドが大きい。可能であればクラス構造化し、`adoStream` オブジェクトを使い回す設計にすることで、メモリ確保のコストを劇的に下げることができる。
データベース連携の罠
取得したバイナリをDBに格納する場合、`ADODB.Recordset` の `AppendChunk` を利用することになる。バイナリを文字列として扱おうとすれば、Nullバイトで文字列が切断されるという初歩的な事故に直面する。常に「バイトの配列」として保持し、I/Oの境界線までその形式を維持せよ。
—
最後に:なぜこれを行うのか
単なる自動化ツールを超え、システム間を繋ぐ「インテグレーター」として振る舞うなら、データの中身を理解しなければならない。
ファイルが壊れているのか、形式が違うのか。それをログに16進数で吐き出せるだけで、トラブルシューティングの時間は1/10になる。このコードは、あなたの現場の「見えないエラー」を可視化するための強力な武器になるはずだ。
さあ、恐れずにバイトの海へ飛び込め。VBScriptの真価は、そこから始まる。
