【テクニカル・上級編】【CSV抽出】FSOで膨大なデータCSVを高速解析し、特定の条件行のみを別ファイルへ抽出バッチ処理 – VBScript (Visual Basic Scripting Edition)解析バイブル

スポンサーリンク

VBScriptを極限まで使い倒せ:数兆行規模のCSVをFSOで「秒速」で捌くアーキテクチャ

現場のエンジニア諸君。未だに「VBScriptは遅い」「大規模データには不向き」などと口にする者がいるようだな。それは言語の限界ではなく、君たちの「実装の限界」に過ぎない。

VBScriptはWindowsの血肉であり、OSの深淵に最も近い言語の一つだ。適切に設計すれば、数兆行のCSVであっても、メモリを汚染することなく、OSのI/Oを極限まで引き出した高速処理が可能だ。今日は、メモリ最適化とI/Oのボトルネックを排除した、伝説級のCSV抽出アーキテクチャを伝授する。

—

1. 勘違いされた「FSO」の真の性能を引き出す

多くの者が、`FileSystemObject (FSO)` を単なる便利なラッパーとしか見ていない。だが、真のアーキテクトは `TextStream` オブジェクトのバッファリング特性を理解している。

してはならないこと:ReadAllとSplitの悪夢

数GB~TB級のデータに対して `ReadAll` を使用するなど論外だ。即座にメモリが枯渇し、仮想メモリへのスワップが発生してシステムは凍結する。「1行ずつ読み、1行ずつ書く(Streaming I/O)」。これが鉄則だ。

必須の最適化:バッファとI/Oの親和性

VBScriptの `OpenTextFile` はデフォルトのバッファサイズが小さい。大規模データを扱う場合、OSのファイルキャッシュをいかに効率的に利用するかが勝負となる。

—

2. 極限の抽出スクリプト:実装コード

以下は、メモリ使用量を一定(定数)に抑えつつ、OSのI/Oを最適化する実装例だ。

Option Explicit

‘ メモリ消費を最小化するための定数定義
Const ForReading = 1
Const ForWriting = 2
Const TristateFalse = 0 ‘ ASCIIとして開く(高速化の鍵)

Sub ExtractTargetCSV(strSourcePath, strDestPath, strTargetDate)
Dim objFSO, objInFile, objOutFile
Dim strLine, arrFields

Set objFSO = CreateObject(“Scripting.FileSystemObject”)

‘ 入力ファイルを読み取り専用、出力ファイルを上書きモードで開く
‘ 巨大ファイルの場合、TristateFalseを指定し、エンコード変換の負荷を避ける
Set objInFile = objFSO.OpenTextFile(strSourcePath, ForReading, False, TristateFalse)
Set objOutFile = objFSO.CreateTextFile(strDestPath, True)

‘ 1行ずつストリームで処理する(メモリ上の負荷は常に1行分のみ)
Do Until objInFile.AtEndOfStream
strLine = objInFile.ReadLine

‘ 文字列操作を最小限にするため、必要であればInStrで判定する
‘ Splitは配列生成コストがあるため、抽出条件が単純なら避けるのが定石
If InStr(strLine, strTargetDate) > 0 Then
objOutFile.WriteLine strLine
End If
Loop

‘ オブジェクトの明示的解放(VBScriptのGCを待たせない)
objInFile.Close
objOutFile.Close

Set objInFile = Nothing
Set objOutFile = Nothing
Set objFSO = Nothing
End Sub

‘ 実行例
Call ExtractTargetCSV(“C:\Data\LargeScale.csv”, “C:\Data\Extracted.csv”, “2023-10-27”)

—

3. シニアエンジニアが意識すべき「隠れたコスト」

① 文字列操作の罠

`Split()` 関数は便利だが、大規模ループ内で多用すると、一時的な配列オブジェクトが大量生成され、ガベージコレクション(GC)の負荷が跳ね上がる。判定条件が明確なら、`InStr()` や `Mid()` を駆使して「メモリを汚さない検索」を行うこと。

② VBScriptの「オブジェクト解放」の作法

VBScriptの `Nothing` 代入は、参照カウントをデクリメントする儀式だ。特に巨大なループ処理の前後やエラーハンドリング時、`Set obj = Nothing` を怠ることはメモリリークへの招待状である。大規模バッチ処理では、`On Error Resume Next` を使いつつ、`Err.Number` を監視する堅牢なエラーハンドリングを必ず実装しろ。

③ Windows APIの活用(さらなる高速化)

もしファイルが数TBに達し、さらに速度を求めるなら、`ScriptControl` を介して `Kernel32.dll` の `ReadFile` を直接叩くことも視野に入れろ。だが、大抵の場合、FSOの `TextStream` を正しく使うだけで、ボトルネックはストレージの物理速度になる。

—

4. 最後に:レガシーを「遺産」にするために

君たちが担当しているのは、単なるスクリプトではない。OSの深層で動く「自動化エンジン」だ。
コードが簡潔であることは、保守性を高める唯一の道だ。数年後に君の後任者がこのコードを読んだとき、「なぜここをこう書いたのか」が明白であるように、コメントには「何をしているか」ではなく「なぜそうしたのか」を記せ。

VBScriptは死んでいない。君たちの設計思想の中で、今もなお現役のアーキテクチャとして生き続けている。
さあ、コンソールを開き、無駄のないI/Oを構築しろ。健闘を祈る。

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