VBScriptで「同期」を語るということ:FSOを使い倒すための極限の作法
ファイルシステムオブジェクト(FSO)は、VBScriptにおける「諸刃の剣」だ。正しく扱えば強力な自動化の武器となるが、ライフサイクル管理を疎かにすれば、メモリリークやハンドルロックを誘発する爆弾と化す。
今回は、2つのフォルダ間で更新日時を比較し、最新版のみを抽出する「差分同期スクリプト」の設計思想を伝授する。単に動くコードを書くのはプログラミングではない。「二度と手を入れる必要がない堅牢な仕組み」を構築することこそ、我々自動化エンジニアの責務だ。
—
1. 差分同期における「思考の罠」と設計方針
多くの初心者は、単純に「フォルダ内のファイルをループして、`DateLastModified` を比較してコピー」というロジックに飛びつく。だが、それでは現場の運用には耐えられない。
- 排他制御の欠如: コピー中に他のプロセスがファイルを書き換えたらどうなるか?
- パスの正規化: 末尾のセパレータ(`\`)の有無で、スクリプトは容易に迷子になる。
- エラーハンドリング: ファイルがロックされている場合、スクリプトが停止してはならない。
今回実装するロジックは、「ソース(コピー元)とターゲット(コピー先)を対等に比較し、常に最新を勝ち残らせる」というアプローチをとる。
—
2. 堅牢な差分同期プロダクションコード
以下のコードは、保守性を考慮し、関数を適切に分離している。そのままコピー&ペーストして環境に合わせてパスを書き換えてほしい。
‘ — 設定エリア —
Const SRC_PATH = “C:\Data\Source”
Const DST_PATH = “D:\Data\Destination”
SyncFolders SRC_PATH, DST_PATH
Sub SyncFolders(sourcePath, destPath)
Dim fso, fldrSrc, fldrDst
Set fso = CreateObject(“Scripting.FileSystemObject”)
‘ パスが存在しない場合のガード節
If Not fso.FolderExists(sourcePath) Or Not fso.FolderExists(destPath) Then
WScript.Echo “エラー: 指定されたフォルダが存在しません。”
Exit Sub
End If
Set fldrSrc = fso.GetFolder(sourcePath)
‘ 同期ロジックの核
Dim file
For Each file In fldrSrc.Files
SyncSingleFile file, destPath, fso
Next
‘ メモリ解放の徹底(VBScriptの基本中の基本)
Set fldrSrc = Nothing
Set fso = Nothing
End Sub
Sub SyncSingleFile(file, destPath, fso)
Dim destFilePath
destFilePath = fso.BuildPath(destPath, file.Name)
‘ ターゲットにファイルが存在しない場合はコピー
If Not fso.FileExists(destFilePath) Then
file.Copy destFilePath, True
WScript.Echo “新規作成: ” & file.Name
Else
‘ 既に存在する場合は更新日時を比較
Dim destFile
Set destFile = fso.GetFile(destFilePath)
‘ ソースが新しい場合のみ上書き
If file.DateLastModified > destFile.DateLastModified Then
file.Copy destFilePath, True
WScript.Echo “更新適用: ” & file.Name
End If
Set destFile = Nothing
End If
End Sub
—
3. なぜこの設計なのか?(アーキテクトの視点)
① `fso.BuildPath` の活用
パスを結合する際、手動で `& “\” &` と書くのは素人のやり方だ。OSのセパレータ環境差異を吸収し、冗長なスラッシュを自動で排除してくれる `BuildPath` を使うのが、プロの最低限の作法である。
② 明示的なメモリ解放
VBScriptはガベージコレクションが強力ではない。特にループ処理内でオブジェクトを生成し続けると、メモリを食いつぶす。`Set obj = Nothing` を省略するエンジニアを、私は「未熟」と判断する。
③ エラーハンドリングの拡張性
今回はシンプルにしているが、本番環境では `On Error Resume Next` を活用し、`Err.Number` をチェックして「ファイルが使用中です」という例外をログに吐き出すロジックを追加すべきだ。
—
4. 実務上の注意点:データベース連携と同期の限界
このスクリプトはファイルシステム上の同期には最適だが、「データベースのレコード同期」をこれで行おうとは考えるな。ファイルにはタイムスタンプがあるが、データベース内のデータ更新には「論理的な順序」が必要であり、ファイル単位の同期ロジックではデータ整合性が崩れるリスクがある。
また、ネットワークドライブ経由での同期を行う際は、必ず `WScript.Sleep 100` などを挟むか、同期の実行タイミングをタスクスケジューラで制御し、重複実行を避ける設計にすること。
最後に:自動化の真髄
「コードを書いて終わり」ではない。自動化エンジニアの真の仕事は、「スクリプトが失敗したときに、いかに迅速に異常を検知し、安全に復旧できるか」という運用設計までをセットで提供することだ。
このスクリプトをベースに、君自身の環境に応じた「堅牢な防壁」を組み込んでほしい。それができた時、君はVBScriptの制約を超えた、真の自動化エンジニアになれるはずだ。
