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

スポンサーリンク

ギガバイト級のログを瞬殺せよ:ADODB.Streamで実現するVBScriptの限界突破高速行数カウント

業務自動化の世界で、VBScriptを「過去の遺物」と切り捨てるのは簡単だ。だが、Windows環境という制約の中で、1GBを超える巨大なログファイルから一瞬で行数を抽出する必要に迫られたとき、君たちはどうする?

`FileSystemObject(FSO)` の `ReadLine` をループさせる? それは自殺行為だ。 1行ずつバッファを解釈し、ストリームポインタを動かすFSOは、現代のストレージ速度を全く活かせない。

今日は、VBScriptの隠された牙である `ADODB.Stream` を駆使し、メモリ効率とI/O性能を極限まで引き上げる「高速行数カウント」の技術を伝授する。

1. なぜFSOではいけないのか:ボトルネックの本質

`FSO.OpenTextFile` は非常に手軽だが、以下の理由で大規模データ処理には適さない。

  • オーバーヘッドの塊: 1行ごとに文字列オブジェクトが生成され、メモリの確保と解放が繰り返される。
  • 同期的なI/O: OSのバッファキャッシュを効率的に利用できず、低速な逐次読み込みに依存する。
  • Unicode変換のコスト: 巨大なファイルを読み込むたびに、内部でエンコーディング変換のコストが発生する。

対して `ADODB.Stream` は、低レベルなバイナリ・バッファ操作に近い挙動が可能であり、ブロック単位での高速な読み込みをサポートしている。

2. 究極のアルゴリズム:バッファ・スキャン法

今回の解法は、「ファイルを一度にメモリへ読み込む(あるいは大きなチャンクで読み込む)」ことと、「文字列置換の差分を利用する」という2つのアプローチを組み合わせる。

VBScriptの `Replace` 関数は非常に高度に最適化されている。これを利用して、「改行コードの数」を力技で数えるのが、実は最も速い。

プロダクションコード:HighSpeedLineCounter.vbs

Option Explicit

‘ 巨大ファイルを高速にカウントする関数
Function GetLineCountFast(strFilePath)
Dim objStream
Dim strContent
Dim strTarget
Dim lngBeforeCount
Dim lngAfterCount

Set objStream = CreateObject(“ADODB.Stream”)

‘ バイナリモードではなくテキストモードで一括読み込み
objStream.Type = 2 ‘ adTypeText
objStream.Charset = “utf-8” ‘ ログのエンコーディングに合わせて変更せよ
objStream.Open
objStream.LoadFromFile strFilePath

‘ 全体を一括読み込み(メモリが許す限り最強)
strContent = objStream.ReadText(-1) ‘ -1 = adReadAll

objStream.Close
Set objStream = Nothing

‘ 改行コード(CRLF)の数をカウントする
‘ 全体長 – 改行を除去した長さ = 改行数
‘ VBScriptのReplaceはネイティブ実装のため驚異的に速い
strTarget = Replace(strContent, vbCrLf, “”)

‘ 簡易的な行数算出(最後の行に改行がない場合を考慮し+1)
GetLineCountFast = (Len(strContent) – Len(strTarget)) / Len(vbCrLf) + 1
End Function

‘ 実行テスト
Dim filePath: filePath = “C:\Logs\massive_log.txt”
WScript.Echo “行数: ” & GetLineCountFast(filePath)

3. 実務で「バグらせない」ための防衛的設計

上記のコードをプロダクション環境へ投入する前に、以下の3点だけは心に刻んでおいてほしい。

① メモリ枯渇への対策

`ADODB.Stream.ReadText(-1)` はファイル全体をメモリにロードする。もしファイルサイズが物理メモリの空き領域(またはVBScriptのプロセス制限)を超える場合は、Chunk読み込みに切り替える必要がある。
一定サイズ(例:100MBずつ)を `ReadText(100000)` で読み込み、そのブロック内の `vbCrLf` を数え上げる手法をとれば、数GBのファイルでも定数メモリで処理可能だ。

② エンコーディングの不一致

ログファイルが `Shift-JIS` なのか `UTF-8` (BOM付き/無し) なのかを誤ると、`ReadText` は文字化けを起こし、改行コードの判定に失敗する。事前に `ADODB.Stream` でバイナリを少し読み込み、BOMを判定するラッパー関数を用意するのが、真のエンジニアというものだ。

③ データベース連携時のトランザクション

このスクリプトで行数を取得した後、SQL ServerやOracleへロードする場合、「カウントして終わり」ではないはずだ。
ストリームを開いている間はファイルをロックする可能性がある。読み込み専用の属性(`adModeRead`)を明示的に指定し、他のプロセスとの競合を避ける設計を忘れてはならない。

結論:道具ではなく、アーキテクチャを理解せよ

VBScriptは古いが、使い手次第で数GBのデータを一瞬で捌く武器になる。
重要なのは、言語の限界を嘆くことではなく、OSが提供するAPIの特性(バッファ、ストリーム、エンコーディング)を正しく理解し、最適化のポイントを突くことだ。

もし君たちの現場で「FSOで遅い」と嘆いている人間がいたら、このコードを投げつけてやってくれ。それが、現場の生産性を底上げする「エンジニアの矜持」というものだ。

さあ、次はどんなボトルネックを排除してやろうか? 質問があればいつでも歓迎する。

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