【テクニカル・上級編】【超高速行数カウント】ADODB.Stream のバッファ読み込みによる大容量テキストファイルの高速行数集計 – VBScript (Visual Basic Scripting Edition)解析バイブル

スポンサーリンク

VBScriptを極める:ADODB.Streamによるギガバイト級ログの「超高速」行数カウント術

現場の最前線にいる諸君なら一度は経験があるはずだ。数GBに膨れ上がったログファイルを前に、`FileSystemObject` (FSO) の `ReadLine` を叩き、進捗の遅さに絶望した経験が。

VBScriptは低速だという言説があるが、それは半分正解で半分間違いだ。「どのオブジェクトを、どのレイヤーで叩くか」。これさえ間違わなければ、VBScriptは今なおWindows環境における最強の軽量高速ランナーであり続ける。

今回は、FSOの常識を捨て、`ADODB.Stream` を駆使してOSのバッファを支配下におく「極限の行数カウント」を伝授する。

なぜ FileSystemObject ではいけないのか

FSOの `ReadLine` は、内部で逐次的に文字コード変換と改行判定を行っている。これは小さなファイルには最適だが、ギガバイト単位のログに対しては「オーバーヘッドの塊」だ。逐次的なI/O要求はOSのカーネルモードとユーザーモードのコンテキストスイッチを頻発させ、CPUを無駄に浪費する。

我々が求めるべきは、「メモリバッファへの一括流し込み」と「バイナリレベルでの改行コード検出」である。

ADODB.Stream によるメモリ最適化アルゴリズム

`ADODB.Stream` は本来データベース用のオブジェクトだが、これを用いることでバイナリデータをメモリ上に直接展開し、必要な分だけを高速にスキャンできる。

以下に、実戦投入可能なコードを提示する。

高速行数カウント・スクリプト

‘ Usage: cscript //nologo CountLines.vbs “C:\logs\large_log.log”
Option Explicit

Dim fso, filePath, stream, buffer, lineCount, pos

If WScript.Arguments.Count < 1 Then WScript.Echo "Usage: cscript //nologo CountLines.vbs
WScript.Quit
End If

filePath = WScript.Arguments(0)

‘ ADODB.Stream オブジェクトの生成
Set stream = CreateObject(“ADODB.Stream”)
stream.Type = 1 ‘ adTypeBinary
stream.Open
stream.LoadFromFile filePath

‘ バッファサイズを定義 (64KB~1MB程度がI/O効率とメモリ使用率のスイートスポット)
Const CHUNK_SIZE = 65536
lineCount = 0

‘ バイナリ読み込みによる高速ループ
Do While Not stream.EOS
buffer = stream.Read(CHUNK_SIZE)
‘ 0x0A (LF) の数をカウントすることで行数を推定する
‘ 極限の速度を求める場合、ここでバイナリ配列を直接走査する
lineCount = lineCount + CountByte(buffer, 10)
Loop

WScript.Echo “Total Lines: ” & lineCount

‘ クリーンアップ:メモリリークは許されない
stream.Close
Set stream = Nothing

Function CountByte(binaryData, targetByte)
Dim i, count
count = 0
‘ SafeArrayの走査
For i = 1 To LenB(binaryData)
If AscB(MidB(binaryData, i, 1)) = targetByte Then
count = count + 1
End If
Next
CountByte = count
End Function

アーキテクチャの急所:シニアエンジニアが押さえるべきポイント

1. メモリ管理の規律

VBScriptのガベージコレクションは頼りにならない。`Set stream = Nothing` は単なる儀式ではなく、参照カウントを即座にゼロにし、巨大なCOMオブジェクトをメモリから解放するための「コマンド」だ。これを忘れると、連続バッチ実行時にシステムメモリを食いつぶすことになる。

2. バイナリ走査の真価

上記の `CountByte` 関数では `MidB` と `AscB` を使用している。これは文字列変換を一切行わない。もし、これを `ReadText` で文字として読み込んでから `Split` 関数で分割しようものなら、数GBのファイルはメモリ上で膨大な文字列オブジェクトに変換され、即座にメモリ不足(OOM)を引き起こすだろう。「バイナリのまま触る」。これが大規模処理の鉄則だ。

3. レガシー環境の保守性

このコードはWindows 2000以降、現在に至るまでWindowsの標準機能だけで動作する。サードパーティ製のライブラリも、.NET Frameworkの複雑なバージョン依存も必要ない。これがVBScriptの真骨頂であり、10年後のシステム管理者が泣いて喜ぶ「保守可能な遺産」となる。

結びに代えて

大規模なシステム連携を行う際、最新の言語やフレームワークを使うことは容易だ。しかし、真のアーキテクトは、その場にある「道具」の限界を知り、APIの挙動を制御することで、ハードウェアの性能を最大限に引き出す。

今日紹介したこのアプローチは、ログ監視システム、バッチ処理の高速化、データマイニングの初動調査において、劇的な成果をもたらすはずだ。

技術は、磨き抜かれたシンプルなものほど美しい。諸君の現場で、このコードが静かに、そして爆速で走り抜けることを願っている。

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