【テクニカル・上級編】【ポーリング処理】FileSystemObject とループ処理による特定フォルダの新規ファイル追加リアルタイム監視 – VBScript (Visual Basic Scripting Edition)解析バイブル

スポンサーリンク

絶望的なレガシー環境を支配せよ:VBScriptによる堅牢なファイル監視アーキテクチャ

多くのシステム管理者が「監視」という言葉を聞いて、真っ先に思い浮かべるのは高価なミドルウェアや複雑なイベント駆動型の仕組みだろう。しかし、我々のような現場の人間は知っている。本当に信頼できるのは、OSの深淵を理解し、泥臭くも確実に動作するスクリプトであることを。

今日は、VBScriptとWSH(Windows Script Host)を用い、極めて低負荷かつ高精度にフォルダを監視する「ポーリング処理」の極意を伝授する。

1. なぜ「監視」は死ぬのか:ポーリングの陥穽

多くの初学者は、単に`Folder.Files`をループで回し、全ファイル名を配列に突っ込んで比較するという「メモリを殺す」実装を行う。これでは監視対象が増えた瞬間にメモリリークを誘発し、WScriptプロセスは肥大化してクラッシュする。

我々が求めるのは、「メモリを消費せず、かつファイルシステムのロック状態を正しく制御できる」実装だ。

2. 堅牢な監視スクリプトの実装

以下に、実戦でそのまま投入できる監視用テンプレートを提示する。ポイントは `Scripting.Dictionary` を用いた高速なインデックス管理と、エラーハンドリングによる「ロック回避」だ。

Option Explicit

‘ 監視設定
Const WATCH_FOLDER = “C:\Inbound”
Const SLEEP_INTERVAL = 1000 ‘ 1秒毎のポーリング

Dim fso, folder, file
Dim dictFiles
Set fso = CreateObject(“Scripting.FileSystemObject”)
Set dictFiles = CreateObject(“Scripting.Dictionary”)

‘ 初回起動時のスナップショット(既存ファイルを検知対象外にする場合)
InitializeState

WScript.Echo “監視を開始しました: ” & WATCH_FOLDER

Do
Set folder = fso.GetFolder(WATCH_FOLDER)

For Each file In folder.Files
If Not dictFiles.Exists(file.Path) Then
‘ 新規ファイルを発見した場合
If IsFileAccessible(file.Path) Then
ProcessFile(file)
dictFiles.Add file.Path, file.DateLastModified
End If
End If
Next

WScript.Sleep SLEEP_INTERVAL
Loop

‘ ファイルのロックを判定する極限の知見
Function IsFileAccessible(filePath)
On Error Resume Next
Dim f
‘ 書き込みモードで開けるかテスト(排他制御の確認)
Set f = fso.OpenTextFile(filePath, 8, False)
If Err.Number = 0 Then
f.Close
IsFileAccessible = True
Else
IsFileAccessible = False
End If
On Error GoTo 0
End Function

Sub ProcessFile(file)
‘ ここに業務ロジックを記述
WScript.Echo “処理開始: ” & file.Name
‘ 処理完了後は適宜移動させるのが鉄則
‘ file.Move “C:\Processed\”
End Sub

Sub InitializeState()
Set folder = fso.GetFolder(WATCH_FOLDER)
For Each file In folder.Files
dictFiles.Add file.Path, file.DateLastModified
Next
End Sub

3. シニアエンジニアが守るべき3つの鉄則

① ファイルロックの「ゆらぎ」を許容せよ

ネットワーク越しや巨大ファイルのコピー中、OSはファイルハンドルを即座に解放しない。`On Error Resume Next` を駆使し、明示的にファイルを開こうと試みることで、ロックされている間は「無視」し、解放された瞬間に処理を開始する。この「待ち」の判断こそが、システムを安定させる。

② 明示的なメモリ解放の哲学

VBScriptのガベージコレクションに頼るな。`Set fso = Nothing` を行う習慣を身につけることは、長期間常駐するスクリプトにおいてメモリ使用量を安定させる唯一の防波堤だ。ただし、ループ内で生成するオブジェクトは、ループ毎に `Nothing` を明示的に代入し、スコープの生存期間を最小化せよ。

③ システム間連携における「移動」の重要性

監視フォルダ内でファイルを処理し続けるのは愚策だ。処理済みのファイルは必ず「別領域」へ移動させること。これにより、ファイルシステム上のインデックス処理を軽量化し、万が一の再起動時にも「どれが未処理か」を迷わなくて済む。

結論:レガシーは廃れない

最新のクラウドネイティブな環境でも、依然として「特定フォルダに置かれたファイルを処理する」という要件は消えない。その際、Dockerコンテナを立ち上げるのか、軽量なWSHスクリプトでOSの隙間を縫うのか。

アーキテクトとしての真価は、「その場に最も適した軽量な解を提示できること」にある。このVBScriptは、20年前のWindows Serverでも、最新のWindows 11でも変わらぬ挙動を約束する。これこそが、技術の真髄というものだ。

君の現場の「自動化」が、このスクリプトによって一歩前進することを願っている。

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