VBScriptの深淵:BOM検知による文字コード自動判別とADODB.Streamの最適運用
VBScriptでファイルシステムを扱う際、多くのエンジニアが犯す過ちは「FSO(FileSystemObject)さえあれば万能だ」という幻想を抱くことだ。FSOは確かに強力だが、それはあくまでASCIIベースのテキスト処理における「平時の兵器」に過ぎない。
システム間連携で文字化けに遭遇したとき、あるいはUTF-8 BOM付き/無しが混在するカオスな環境に放り込まれたとき、諸君らが頼るべきはADODB.Streamとバイナリ操作の知見だ。今回は、現場でトラブルを完封するための「文字コード自動判別・動的切替エンジン」の設計思想を伝授する。
—
1. なぜFSOだけでは不十分なのか
FSOの`OpenTextFile`メソッドは、システムロケールの規定値(多くの場合Shift-JIS)でファイルを読み込む。UTF-8のファイルを読み込もうとすれば、そこには悲劇的な文字化けが待っている。
我々が目指すべきは、「ファイルを開く前に、先頭数バイトのシグネチャを読み取り、適切なストリームに流し込む」という戦略的アプローチだ。
2. 実践:文字コード判定ライブラリの極意
以下のコードは、バイナリとして先頭4バイトを切り出し、BOM(Byte Order Mark)を判定するロジックだ。ここで重要なのは、メモリリークを避けるためにADODB.Streamを適切に使い分け、即座に解放することである。
‘ — 文字コード自動判定・読み込みエンジン —
Function ReadFileAutoDetect(strPath)
Dim adoStream, binHead, enc
Set adoStream = CreateObject(“ADODB.Stream”)
‘ バイナリとして先頭4バイトを読み込む
adoStream.Type = 1 ‘ adTypeBinary
adoStream.Open
adoStream.LoadFromFile strPath
binHead = adoStream.Read(4)
adoStream.Close
‘ BOM判定ロジック
‘ UTF-8: EF BB BF / UTF-16 BE: FE FF / UTF-16 LE: FF FE
Dim b1, b2, b3
b1 = AscB(MidB(binHead, 1, 1))
b2 = AscB(MidB(binHead, 2, 1))
b3 = AscB(MidB(binHead, 3, 1))
If b1 = &HEF And b2 = &HBB And b3 = &HBF Then
enc = “UTF-8”
ElseIf b1 = &HFF And b2 = &HFE Then
enc = “UTF-16LE”
ElseIf b1 = &HFE And b2 = &HFF Then
enc = “UTF-16BE”
Else
enc = “Shift_JIS” ‘ デフォルトはレガシーを想定
End If
‘ 再度読み込み(テキストモードへ切替)
adoStream.Type = 2 ‘ adTypeText
adoStream.Charset = enc
adoStream.Open
adoStream.LoadFromFile strPath
ReadFileAutoDetect = adoStream.ReadText
‘ 明示的な解放:ここを怠るとCOMオブジェクトがメモリに滞留する
adoStream.Close
Set adoStream = Nothing
End Function
—
3. シニアアーキテクトが教える「運用の鉄則」
オブジェクトのライフサイクル管理
VBScriptにおいて`Set object = Nothing`を省略するのは甘えだ。特に、大量のファイルをバッチ処理でループさせる場合、ADODB.Streamの解放遅延は即座にメモリ消費量の増大を招く。`On Error Resume Next`と組み合わせた厳密なエラーハンドリングと共に、例外発生時も必ず閉じる実装を徹底せよ。
ADODB.StreamのCharset選択
`Charset`プロパティには、Windowsがサポートするエンコード文字列を渡す必要がある。
- UTF-8を指定する際は、単に”UTF-8″とする。
- 注意すべきは、ADODB.Streamで読み込む際、BOM無しのUTF-8は非常に判定が困難であることだ。もしファイルが「BOM無しUTF-8」であることが確定しているなら、バイナリ変換を行うよりも、ADODB.Streamを使わずにWindows APIの`MultiByteToWideChar`を呼び出すか、素直にスクリプトの実行環境自体をUnicode対応させるべきだ。
パフォーマンスの極限
この手法は、ファイルを二度開いているように見えるかもしれないが、OSのファイルキャッシュが効いているため、実用上のパフォーマンス低下は無視できるレベルだ。逆に、全ファイルを力技で読み込んでから文字コードを判別するよりも、先頭数バイトのバイナリチェックで済ませる方が、I/O負荷は圧倒的に低い。
—
結びに代えて:レガシーを支配するということ
VBScriptは、もはや「過去の遺物」と揶揄されることもある。しかし、インフラの深部や、クラウド移行の過渡期にあるレガシーシステムにおいて、この「OS標準機能だけで完結する」という特性は、依然として最強の武器だ。
ライブラリを組む際は、常に「自分が死んだ後、誰がこのコードを保守するのか」を考えろ。バイナリ定数をマジックナンバーとして埋め込むのではなく、適切な定数定義を行い、読み手が仕様を即座に理解できる構造を維持する。それが、真に「掌握する」ということだ。
諸君、コードを書け。ただし、ただ動くコードではなく、OSの挙動とメモリの呼吸を感じるコードを。
