【実務・中級編】【超巨大ログ分割】数GBクラスのテキストをFSOで指定行数ごとに高速で小分けファイル出力する軽量バッチ – VBScript (Visual Basic Scripting Edition)解析バイブル

スポンサーリンク

【超巨大ログ分割】数GBクラスのテキストをFSOで指定行数ごとに高速で小分けファイル出力する軽量バッチ

開発現場で絶望を味わう瞬間の一つが、数GBに達する巨大なサーバーログの解析を迫られた時だ。メモ帳などのテキストエディタで開こうものなら、一発でメモリを食い潰してフリーズする。かといって、専用の解析ツールを入れる権限もない閉じた環境——。

こうした現場のインシデント対応や日次バッチにおいて、VBScript(Visual Basic Scripting Edition)は今なお「OS標準で追加インストール不要の最強の特攻兵器」として機能する。

しかし、FSO(FileSystemObject)の扱いを少しでも誤れば、スクリプトは途中でメモリリークを起こし、あるいは処理速度が極限まで低下して使い物にならなくなる。

今回は、数GBクラスの巨大ログを安全かつ高速に指定行数で分割し、プロダクション環境でそのまま使える堅牢なVBScript製スプリッターの設計思想と実装を伝授する。

—

1. なぜ愚直なFSOコードは破綻するのか?(アンチパターンの排除)

多くのプログラマブルな初心者がやりがちな間違いは、巨大ファイルを扱う際に「一度全行を配列やメモリ上に読み込もうとする」ことだ。

`ReadAll` や `Read` を大容量ファイルに対して実行すれば、VBScriptの背後にあるCOMコンポーネントはメモリ上に巨大な文字列バッファを確保しようとし、Out of Memory(メモリ不足)エラーで即死する。

鉄則:ストリーミング処理の徹底

FSOの `TextStream` オブジェクトが持つ `AtEndOfStream` と `ReadLine` を組み合わせ、「一行ずつ読み、一行ずつ書き出す」ストリーミング処理を徹底しなければならない。メモリ上に保持するのは、常に「たった今読み込んだ1行の文字列」のみ。これにより、メモリ消費量はファイルサイズに依存せず、常に$O(1)$の一定を保つ。

—

2. 堅牢な分割バッチの設計要件

実務で耐えうるスクリプトにするためには、以下の要件を満たす必要がある。

1. 文字コードの安全なハンドリング

  • Windows環境のログはShift-JIS(CP932)やUTF-8(BOM付き/無し)が混在する。FSOの `OpenTextFile` の第3引数(Unicode指定)の挙動を正しく理解し、文字化けを防ぐ。

2. ゼロ埋め連番ファイル名

  • `log_1.txt`, `log_2.txt` とすると、ファイル一覧でのソートが崩れる。`log_0001.txt` のようにゼロパディングされた美しい連番を生成する。

3. 例外処理(Errオブジェクトの制御)

  • 巨大ファイル処理中にディスク容量不足やファイルロックが発生した場合でも、ストリームを確実に閉じ(Resource Leakの防止)、異常終了を検知できるようにする。

—

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

以下のコードをメモ帳に貼り付け、拡張子を `.vbs` として保存してほしい。数GBのログファイルを秒速で指定行数ごとに分割する。

‘ ==============================================================================
‘ Script Name : HighSpeedLogSplitter.vbs
‘ Description : 数GBクラスの巨大ログを指定行数ごとに高速で連番分割する実用バッチ
‘ Author : 業務自動化アーキテクト
‘ ==============================================================================
Option Explicit

‘ — 設定エリア —
Const SOURCE_FILE_PATH = “C:\Logs\huge_server.log” ‘ 分割対象の巨大ログパス
Const OUTPUT_DIR = “C:\Logs\split_out\” ‘ 出力先フォルダ(末尾に必ず\を付与)
Const LINES_PER_FILE = 100000 ‘ 1ファイルあたりの最大行数(例: 10万行)
Const FORCED_UNICODE = False ‘ True:Unicode(UTF-16), False:ASCII/SJIS

Sub SplitHugeLog()
Dim fso, tsRead, tsWrite
Dim lineCount, fileIndex
Dim currentOutputPath, baseName, ext
Dim dotPos

‘ 処理時間計測用
Dim startTime
startTime = Timer

Set fso = CreateObject(“Scripting.FileSystemObject”)

‘ 1. 前提条件のバリデーション
If Not fso.FileExists(SOURCE_FILE_PATH) Then
WScript.Echo “[ERROR] 入力ファイルが存在しません: ” & SOURCE_FILE_PATH
Exit Sub
End If

If Not fso.FolderExists(OUTPUT_DIR) Then
‘ 出力先がない場合は自動生成
fso.CreateFolder(OUTPUT_DIR)
End If

‘ 2. 読み込み専用でソースを開く (ForReading = 1)
‘ ※第3引数のTristateは環境に合わせて調整 (-2:システムデフォルト, 0:ASCII, -1:Unicode)
On Error Resume Next
Set tsRead = fso.OpenTextFile(SOURCE_FILE_PATH, 1, False, 0)
If Err.Number <> 0 Then
WScript.Echo “[CRITICAL] ファイルのオープンに失敗しました: ” & Err.Description
Exit Sub
End If
On Error GoTo 0

lineCount = 0
fileIndex = 1

‘ 拡張子の分離(例: log.txt -> base=”log”, ext=”txt”)
baseName = fso.GetBaseName(SOURCE_FILE_PATH)
ext = fso.GetExtensionName(SOURCE_FILE_PATH)

WScript.Echo “[INFO] ログの分割処理を開始します…”

‘ 3. ストリーミング・メインループ
Do While Not tsRead.AtEndOfStream

‘ 指定行数に達した、または初回の場合、出力ファイルを開き直す
If lineCount Mod LINES_PER_FILE = 0 Then
If Not tsWrite Is Nothing Then tsWrite.Close

‘ 4桁のゼロ埋め連番ファイル名を生成 (例: huge_0001.txt)
currentOutputPath = OUTPUT_DIR & baseName & “_” & Right(“0000” & fileIndex, 4) & “.” & ext

‘ 書き込み用としてファイルを作成 (ForWriting = 2, Create = True)
Set tsWrite = fso.CreateTextFile(currentOutputPath, True, FORCED_UNICODE)

fileIndex = fileIndex + 1
End If

‘ 1行読み込んで書き出す(メモリ効率の極限)
tsWrite.WriteLine tsRead.ReadLine
lineCount = lineCount + 1

‘ 進捗を10万行ごとにコンソール出力(フリーズ感を防ぐ)
If lineCount Mod 100000 = 0 Then
WScript.Echo “[PROGRESS] ” & FormatNumber(lineCount, 0) & ” 行処理完了…”
End If
Loop

‘ 4. クリーンアップ(リソースの確実な解放)
If Not tsRead Is Nothing Then tsRead.Close
If Not tsWrite Is Nothing Then tsWrite.Close

Set tsRead = Nothing
Set tsWrite = Nothing
Set fso = Nothing

WScript.Echo “[SUCCESS] すべての分割処理が完了しました。総処理行数: ” & FormatNumber(lineCount, 0) & “行 / 所要時間: ” & FormatNumber(Timer – startTime, 2) & “秒”

End Sub

‘ 処理実行
SplitHugeLog()

—

ジ

実務でこのスクリプトを運用するにあたり、以下のポイントを心に留めておいてほしい。

  • ディスクI/Oのボトルネック

数GBの書き出しを行うため、HDDではなくSSD環境で実行することを強く推奨する。HDDでは書き込みヘッドのシークがボトルネックになり、VBScript本来の速度が出ない。

  • 文字コードの罠

もし出力されたファイルが文字化けする場合は、`OpenTextFile` の第4引数(Tristate)や `CreateTextFile` の `FORCED_UNICODE` フラグ(UTF-16になる点に注意)を、対象ログのエンコーディングに合わせて調整してほしい。UTF-8(BOMなし)を厳密に扱いたい場合はADODB.Streamの併用を検討すべきだが、純粋なFSOの速度とシンプルさを取るなら上記設計が最も堅牢である。

枯れた技術であるVBScriptであっても、適切な設計思想(ストリーミング処理とリソース管理)の元に書かれれば、モダンな言語のスクリプトに引けを取らない高いパフォーマンスを発揮する。現場のシステム管理や急なデータ分析案件において、本記事の知見があなたの武器となることを確信している。

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