【実務・中級編】【初心者向け】TextStreamのCloseメソッドを安全に呼ぶためのExit Sub/Function時のリソース解放の基本パターン – VBScript (Visual Basic Scripting Edition)解析バイブル

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

VBScriptにおける「ゾンビ・ファイルロック」を根絶せよ:TextStreamの安全な解放と堅牢なエラーハンドリング設計術

業務自動化の現場で、現場のプロフェッショナルと「素人」を分かつ境界線はどこにあるか?
それは、「正常系が動くコード」を書けるか、それとも「異常系でもリソースを制御できるコード」を書けるか、という一点に集約される。

特にVBScriptを用いたファイル操作において、多くの開発者が陥る罠がある。それが「TextStreamの解放漏れによるファイルロック」だ。

処理の途中で条件分岐によって `Exit Sub` や `Exit Function` を実行した際、開いたままのファイルがOSレベルでロックされ続け、次回の実行時に「書き込み権限がありません」というエラーで自爆する。これは、スケジュール実行されるバッチ処理において致命的な設計ミスである。

本稿では、伝説的なアーキテクトの視点から、TextStreamを確実に、かつ安全にクローズするための「究極のリソース管理パターン」を伝授する。

1. なぜ「ただの Close」では不十分なのか

初心者はこう書く。
「処理が終わったら `ts.Close` を呼べばいい。文句はないはずだ」と。

しかし、実務のコードはそんなに甘くない。以下のシナリオを想像してほしい。

1. ファイルを開く。
2. ファイルの中身を解析する。
3. 解析中に予期せぬエラーが発生する(または特定の条件で処理を中断する)。
4. `Exit Sub` で関数を抜ける。
5. `ts.Close` が実行されないまま関数が終了する。

この瞬間、OSは「このファイルはまだ使用中である」と判断し、ファイルハンドルを保持し続ける。これがゾンビ・ファイルロックだ。この状態になると、手動でプロセスをキルするか、OSの再起動を待たなければ、そのファイルは二度と操作できない。

2. 堅牢な設計思想:Single Exit Point(単一出口)原則

プロフェッショナルな設計における鉄則は、「関数の出口は常に一つであるべき」という考え方だ。

`Exit Sub` をあちこちに散布するのではなく、エラーが発生しても、途中で条件を満たしても、必ず必ず「クリーンアップ処理」を通るルートを通るように設計しなければならない。

VBScriptには `try…finally` 構文が存在しない。そのため、我々は `On Error GoTo` を駆使し、構造化されたエラーハンドリングとクリーンアップ・ブロックを自前で構築する必要がある。

3. 【実践】プロダクション品質のコードパターン

以下に、私が現場で標準として推奨している、最も堅牢なファイル読み込み関数のテンプレートを示す。これをコピペして使い、型を理解せよ。

'**
' Function: SafeReadFile
' Description: ファイルを安全に読み込み、リソースを確実に解放する
' Arguments: strFilePath (String) - 対象ファイルのフルパス
' Returns: String - ファイルの内容。失敗時は空文字。
'**
Function SafeReadFile(strFilePath)
    Dim fso, ts, strContent
    Dim bSuccess
    
    ' 初期化:変数は必ず初期値(Nothingや空文字)で始める
    Set fso = Nothing
    Set ts = Nothing
    strContent = ""
    bSuccess = False

    ' エラーハンドリングの開始
    On Error GoTo ErrorHandler

    ' 1. オブジェクトの生成
    Set fso = CreateObject("Scripting.FileSystemObject")

    ' 2. ファイルの存在確認(防御的プログラミング)
    If Not fso.FileExists(strFilePath) Then
        Err.Raise 1, "SafeReadFile", "指定されたファイルが存在しません: " & strFilePath
    End If

    ' 3. ファイルのオープン (ForReading = 1)
    Set ts = fso.OpenTextFile(strFilePath, 1)

    ' 4. データ読み込み
    ' ※ここで巨大なファイルを扱う場合は、一行ずつ読み込む等のメモリ対策が必要
    strContent = ts.ReadAll

    ' すべての工程が正常に完了した場合のみ成功フラグを立てる
    bSuccess = True

' --- 正常終了ルート ---
ExitFunction:
    ' ここが「単一の出口」となる。
    ' 正常時もエラー時も、必ずこのクリーンアップ処理を通る。
    Call Cleanup(fso, ts)
    SafeReadFile = strContent
    Exit Function

' --- エラーハンドリングルート ---
ErrorHandler:
    ' エラーログの出力(実務ではログファイルへの書き出しを推奨)
    MsgBox "Critical Error in SafeReadFile" & vbCrLf & _
           "Error No: " & Err.Number & vbCrLf & _
           "Description: " & Err.Description, vbCritical
    
    ' エラーが発生した場合は、成功フラグをFalseのままにしてExitFunctionへ飛ばす
    Resume ExitFunction

End Function

'**
' Sub: Cleanup
' Description: リソースの解放を専門に行う内部用サブルーチン
'**
Sub Cleanup(objFSO, objTS)
    On Error Resume Next ' クリーンアップ中のエラーで止まらないよう、二重の防御を施す

    ' TextStreamのクローズ
    ' オブジェクトがNothingでないことを確認してからCloseを呼ぶのが作法
    If Not objTS Is Nothing Then
        objTS.Close
        Set objTS = Nothing
    End If

    ' FileSystemObjectの解放
    If Not objFSO Is Nothing Then
        Set objFSO = Nothing
    End If
    
    On Error GoTo 0
End Sub

' --- テスト実行 ---
Dim result
result = SafeReadFile("C:\Test\SampleData.txt")
If result <> "" Then
    WScript.Echo "読み込み成功: " & Left(result, 50) & "..."
End If

4. アーキテクトによる技術解説:なぜこのコードが「強い」のか

このコードには、業務自動化を支える3つの重要なテクニックが組み込まれている。

① `Cleanup` サブルーチンの分離

`Close` メソッドと `Set obj = Nothing` を一箇所に集約している。これにより、メインロジックの中に「後始末」のコードが混在して読みづらくなるのを防ぎ、かつ、「どこで抜けても必ず後始末が実行される」という保証を与えている。

② `On Error Resume Next` の戦略的配置

`Cleanup` サブルーチン内で `On Error Resume Next` を使用している。これは非常に重要だ。もし `ts.Close` を実行しようとした際に、既にファイルが何らかの理由で閉じられていた場合、そこでエラーが発生すると、せっかくのエラーハンドリング自体がクラッシュする。「後始末中にエラーが起きても、絶対に処理を止めない」。これがプロの防御策だ。

③ オブジェクトのライフサイクル管理

`Close` は「ファイルハンドル(OSとの接続)」を解放し、`Set obj = Nothing` は「メモリ上のオブジェクト(COMリソース)」を解放する。

  • `Close` だけでは、メモリリークの可能性がある。
  • `Nothing` だけでは、ファイルロックが解除されない可能性がある。

この両方をセットで行うことこそが、リソース管理の完遂である。

5. まとめ:自動化エンジニアとしての規律

VBScriptは古くからある言語であり、モダンな言語のような強力な例外処理機構を持っていない。だからこそ、エンジニアの設計思想がそのままシステムの安定性に直結する。

「動けばいい」という思考を捨て、「どう壊れるか」「どうやって確実に片付けるか」を常に問い続けなさい。この `Single Exit Point` と `Dedicated Cleanup` のパターンを血肉にすることが、信頼されるエンジニアへの第一歩である。

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