【VBScript極致】FSOとDictionaryで構築する超高速ファイル差分エンジン
システム運用の現場において、数万、数十万におよぶファイルの整合性チェックを求められたとき、安易に二重ループを回すようなコーディングをしてはならない。それはエンジニアとしての敗北であり、サーバーリソースへの冒涜だ。
今日は、VBScriptの限界を知り尽くした諸君に向けて、`Scripting.FileSystemObject`(以下FSO)と`Scripting.Dictionary`を高度に組み合わせ、計算量 $O(n+m)$ で差分を弾き出す、プロフェッショナルなファイル存在差分マトリックス生成の手法を伝授する。
—
1. なぜ「Dictionary」なのか:計算量の呪縛を解く
二つのフォルダ(A, B)を比較する際、最も陥りやすい罠は、フォルダAのファイル名でループを回し、その中で毎回フォルダBのファイル群を走査する「$O(n \times m)$ の地獄」だ。ファイル数が数千を超えた瞬間、スクリプトはフリーズする。
我々が取るべき戦略は、「ハッシュテーブル(Dictionary)によるインデックス化」である。
1. フォルダAのファイルリストをDictionaryに登録する(Key: ファイル名, Value: メタデータ)。
2. フォルダBのファイルリストを走査し、Dictionaryに存在するかを即座に判定する。
3. この手法であれば、探索コストは実質 $O(1)$。大規模ファイルシステムでも瞬時に結果が出る。
—
2. 極限のコード:ファイル差分マトリックス・エンジン
以下に、メモリ効率と実行速度を最優先した実装を示す。`Option Explicit`の徹底は当然として、オブジェクトのライフサイクル管理に注目してほしい。
Option Explicit
‘ — コンフィグ設定 —
Const FOLDER_A = “C:\Path\To\Source”
Const FOLDER_B = “C:\Path\To\Dest”
Call CompareFolders(FOLDER_A, FOLDER_B)
Sub CompareFolders(path1, path2)
Dim fso, dictA, dictB
Dim folderA, folderB, file
Set fso = CreateObject(“Scripting.FileSystemObject”)
Set dictA = CreateObject(“Scripting.Dictionary”)
Set dictB = CreateObject(“Scripting.Dictionary”)
‘ メモリ最適化のため、必要最小限のデータのみをDictionaryに格納する
Set folderA = fso.GetFolder(path1)
For Each file In folderA.Files
dictA.Add file.Name, file.DateLastModified
Next
Set folderB = fso.GetFolder(path2)
For Each file In folderB.Files
dictB.Add file.Name, file.DateLastModified
Next
‘ 比較処理:両方・片方のみの判定
WScript.Echo “— 比較レポート —”
‘ フォルダAを基準に走査
Dim key
For Each key In dictA.Keys
If dictB.Exists(key) Then
WScript.Echo “[両方に存在] ” & key
Else
WScript.Echo “[Aのみ存在] ” & key
End If
Next
‘ フォルダBのみ存在を確認
For Each key In dictB.Keys
If Not dictA.Exists(key) Then
WScript.Echo “[Bのみ存在] ” & key
End If
Next
‘ 【重要】オブジェクトの明示的解放(VBScriptのGCに頼らない)
Set dictA = Nothing
Set dictB = Nothing
Set folderA = Nothing
Set folderB = Nothing
Set fso = Nothing
End Sub
—
3. シニアエンジニアが押さえるべき「最適化の要諦」
オブジェクトの明示的解放
VBScriptは参照カウンタ方式のガベージコレクションを採用している。`Set obj = Nothing` を省略することは、大規模なループ処理においてメモリリークを誘発する最大の要因だ。特にファイルシステム操作のような外部COMオブジェクトを扱う場合、明示的な解放はコードの規律である。
大規模ファイル操作における「限界」
もし対象が数百万ファイルを超える場合、Dictionaryのメモリ消費が物理メモリを圧迫し始める。その際は、Dictionaryに全てを保持するのではなく、一時ファイルにパスを書き出し、`Sort`コマンドでソートしてから比較する手法へ切り替えるべきだ。これがエンジニアの「引き出しの深さ」である。
レガシー環境の保守における注意点
Windows Server 2003/2008などの古い環境では、FSOの `GetFolder` メソッドがネットワークドライブに対して極端に遅くなることがある。その際は、WMI (`Win32_LogicalFileSecuritySetting` 等) の使用を検討するのではなく、`cmd` の `dir /b /s` を実行し、そのストリームを `StdOut` で受け取る手法が、実は最も高速で堅牢だ。
—
結び:技術は「美学」である
ツールは手段に過ぎない。しかし、その手段にどれだけの「配慮」を込めたかによって、システムの寿命は数年変わる。
VBScriptは古く見えるかもしれない。だが、Windows OSが存続する限り、それは最強の「現場の武器」であり続ける。諸君が今日書く数行のコードが、明日、誰かの夜中の緊急呼び出しを未然に防ぐことを期待している。
健闘を祈る。
