【入門編】【上級プロフェッショナル向け】FSOで差分定義テキスト(Patch形式)をパースしターゲット設定ファイルを自動更新・適用する簡易パッチ適用エンジン – VBScript (Visual Basic Scripting Edition)解析バイブル

スポンサーリンク
スポンサーリンク

脱・マクロ記録!FSOとDictionaryを操り、設定ファイルを自動更新する「パッチ適用エンジン」の構築

こんにちは。自動化の世界へようこそ。

「マクロの記録」を使って、ボタン一つでExcelが動く。それは素晴らしい第一歩です。しかし、あなたがもし「システムの設定ファイルを書き換えたい」「大量の構成ファイルを一括で、しかも安全に更新したい」と願うなら、その先にある「ロジックによる制御」の領域へ踏み出す必要があります。

今日、私たちが挑戦するのは、単なるファイル操作ではありません。
「差分定義ファイル(パッチ)を読み込み、ターゲットの設定ファイルを、バックアップを取りながら安全に書き換える」という、インフラ自動化の極めて実践的なエンジンの構築です。

このコードを理解したとき、あなたは「記録された操作」をなぞるユーザーから、「仕組みを作る」エンジニアへと進化を遂げているはずですよ。

1. 戦略の設計図:なぜ「FSO」と「Dictionary」なのか?

このツールを作るにあたり、2つの強力な武器を手に取ります。

FileSystemObject (FSO) :ファイル操作の司令塔

FSOは、ファイルの存在確認、コピー、削除、そして中身の読み書きを司るオブジェクトです。しかし、プロフェッショナルはただ「開く」だけではありません。「ファイルが既に存在するか?」「書き込み権限はあるか?」といった生存確認を徹底することで、システムの暴走を防ぎます。

Scripting.Dictionary :メモリ上の高速な作業机

ここが今日一番の「知恵」です。
テキストファイルを1行ずつ読み込んで、特定の行を探して書き換える……。そんな非効率なことはしません。
まず、ターゲットとなる設定ファイルを丸ごと Dictionary(連想配列) という「メモリ上の作業机」に展開します。

  • Key(鍵): 設定項目の名前(例:`ServerIP`)
  • Item(値): その設定値(例:`192.168.1.1`)

Dictionaryを使えば、特定の項目を「一瞬で」見つけ出し、追加したり、消したり、書き換えたりできます。最後に、その机の上をファイルに書き戻す。これが最も高速で、かつロジックが明快な手法です。

2. パッチ形式の定義

今回は、以下のようなシンプルな「パッチファイル(`.patch`)」を解析する仕様にします。

命令 書式 内容
ADD `ADD Key Value` 新しい設定を追加する
SET `SET Key Value` 既存の設定を更新する
DEL `DEL Key` 設定を削除する

3. 実装:簡易パッチ適用エンジン

それでは、魂を込めて書いたコードをご覧ください。このまま `.vbs` ファイルとして保存して動かすことができます。

' ==========================================================================
' Engine Name: Professional Patch Application Engine
' Description: FSO and Dictionaryを利用した設定ファイル自動更新ツール
' Author: Legend Architect
' ==========================================================================

Option Explicit

' --- メイン処理 ---
Sub Main()
    Dim fso, patchFile, targetFile
    
    ' パスは環境に合わせて変更してください
    patchFile  = "config.patch"
    targetFile = "settings.conf"
    
    Set fso = CreateObject("Scripting.FileSystemObject")
    
    ' 1. 事前チェック
    If Not fso.FileExists(patchFile) Then
        MsgBox "エラー: パッチファイルが見つかりません。" & vbCrLf & patchFile, vbCritical
        Exit Sub
    End If
    
    If Not fso.FileExists(targetFile) Then
        MsgBox "エラー: ターゲットファイルが見つかりません。" & vbCrLf & targetFile, vbCritical
        Exit Sub
    End If

    ' 2. 安全のためのバックアップ作成
    ' 失敗した時に元の状態に戻せるよう、プロの現場では必須の工程です
    On Error Resume Next
    fso.CopyFile targetFile, targetFile & ".bak", True
    If Err.Number <> 0 Then
        MsgBox "エラー: バックアップの作成に失敗しました。書き込み権限を確認してください。", vbCritical
        Exit Sub
    End If
    On Error GoTo 0

    ' 3. パッチ適用実行
    If ApplyPatch(patchFile, targetFile) Then
        MsgBox "パッチの適用が完了しました!" & vbCrLf & "バックアップ: " & targetFile & ".bak", vbInformation
    Else
        MsgBox "パッチの適用中にエラーが発生しました。", vbExclamation
    End If

    Set fso = Nothing
End Sub

' --- パッチ適用ロジック ---
Function ApplyPatch(strPatchPath, strTargetPath)
    Dim fso, dict, ts, line, parts
    Dim strLine, strKey, strValue, strCommand
    
    Set fso = CreateObject("Scripting.FileSystemObject")
    Set dict = CreateObject("Scripting.Dictionary")
    ApplyPatch = False ' デフォルトは失敗

    ' --- STEP A: ターゲットファイルをDictionaryにロード ---
    ' 設定ファイルを「Key=Value」形式と想定して読み込みます
    Set ts = fso.OpenTextFile(strTargetPath, 1) ' 1 = ForReading
    Do Until ts.AtEndOfStream
        strLine = Trim(ts.ReadLine)
        If strLine <> "" And InStr(strLine, "=") > 0 Then
            parts = Split(strLine, "=")
            ' KeyとValueを分離して格納
            dict.Add Trim(parts(0)), Trim(parts(1))
        End If
    Loop
    ts.Close

    ' --- STEP B: パッチファイルを解析してDictionaryを操作 ---
    Set ts = fso.OpenTextFile(strPatchPath, 1)
    Do Until ts.AtEndOfStream
        strLine = Trim(ts.ReadLine)
        If strLine <> "" Then
            ' 区切り文字 "|" で分割
            parts = Split(strLine, "|")
            strCommand = parts(0) ' ADD, SET, DEL
            
            Select Case strCommand
                Case "ADD"
                    strKey = Trim(parts(1))
                    strValue = Trim(parts(2))
                    If Not dict.Exists(strKey) Then
                        dict.Add strKey, strValue
                    End If
                
                Case "SET"
                    strKey = Trim(parts(1))
                    strValue = Trim(parts(2))
                    If dict.Exists(strKey) Then
                        dict(strKey) = strValue
                    End If
                
                Case "DEL"
                    strKey = Trim(parts(1))
                    If dict.Exists(strKey) Then
                        dict.Remove strKey
                    End If
            End Select
        End If
    Loop
    ts.Close

    ' --- STEP C: 更新されたDictionaryをファイルに書き戻す ---
    ' 一旦、既存のファイルを上書き(または新規作成)します
    Set ts = fso.CreateTextFile(strTargetPath, True)
    Dim k
    For Each k In dict.Keys
        ts.WriteLine k & "=" & dict(k)
    Next
    ts.Close

    ApplyPatch = True ' すべて成功
    Set dict = Nothing
    Set fso = Nothing
End Function

' 実行
Main

4. ここがプロの分かれ道:陥りやすいエラーと回避策

このコードを動かして「あれ?」と思ったとき、あなたはエンジニアとして成長しています。以下の3点は、現場で必ず直面する壁です。

① ファイルの「掴み(ロック)」問題

`OpenTextFile` でファイルを開いたまま、同じファイルに対して `CreateTextFile` で書き込もうとすると、「書き込み禁止」のエラーが出ます。
解決策: 必ず `ts.Close` を呼び出し、ファイルへのアクセス権を解放してから次の操作に移る。これはオブジェクトのライフサイクル管理の基本です。

② エンコーディングの罠

VBScriptのFSOは、デフォルトでは「ANSI(Shift-JIS)」として動作します。もしターゲットファイルが「UTF-8」で保存されている場合、日本語が文字化けしたり、ファイル構造が壊れたりします。
解決策: システム全体の文字コードを確認するか、必要に応じてADODB.Streamオブジェクトを使用してUTF-8を扱う高度な手法を検討してください。

③ Dictionaryの「重複」エラー

`dict.Add` メソッドは、既に存在するKeyを追加しようとすると、即座にランタイムエラーを吐いて停止します。
解決策: `If Not dict.Exists(strKey) Then` を使い、存在確認を行ってから追加する。この「慎重さ」が、止まらないプログラムを作ります。

最後に

いかがでしたか?
単に「ファイルの中身を書き換える」という動作の裏側には、「データの持ち方(Dictionary)」「安全性の確保(Backup)」「解析のロジック(Parsing)」という、エンジニアリングの神髄が詰まっています。

このコードをベースに、例えば「削除した項目をログに残す機能」や「設定値のバリデーション(数値かどうかチェックする)機能」を追加してみてください。それが、あなた独自の「最強のツール」への道です。

一歩ずつ、確実に。次はもっと複雑な自動化の戦場で会いましょう!

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