【テクニカル・上級編】【安全な一時ファイル管理】GUID風ランダム文字列生成アルゴリズムと他プロセスとの競合回避型Temp処理 – VBScript (Visual Basic Scripting Edition)解析バイブル

スポンサーリンク

VBScriptを支配せよ:競合を許さない「極限の一時ファイル管理」戦略

レガシーシステムの深淵で戦う諸君。VBScriptは「古い言語」ではない。OSの深層に最も近い場所で、軽量かつ強力に動作する「シェル・インテグレータ」である。

だが、WSH(Windows Script Host)環境において、複数のスクリプトが並列稼働するマルチプロセス環境下で最も忌むべき存在、それが「エラー70:書き込み権限がありません(ファイル競合)」だ。安易な `Temp` フォルダの使用は、システム全体の脆弱性を招く。

本稿では、プロセス間競合を物理的に排除し、メモリリークを許さない、プロフェッショナルな「一時ファイル管理モジュール」を提示する。

1. GUID生成の神話と現実

多くのプログラマは、一時ファイル名に単なるタイムスタンプを用いる。これは愚策だ。ミリ秒単位の競合を許す設計は、システム管理者としては失格である。

真にユニークなIDが必要ならば、Windows APIの `CoCreateGuid` を利用するのが正攻法だが、VBScript単体でDLL呼び出しを行うのはオーバーヘッドが大きい。そこで我々は、`TypeLib` を介さず、ネイティブな乱数生成アルゴリズムを用いて、十分な衝突回避能力を持つ「疑似GUID」を生成する。

実装:衝突確率を極限まで下げるアルゴリズム

‘ ——————————————————————
‘ @Function: GetUniqueTempPath
‘ @Desc: プロセスIDと高精度乱数を組み合わせたユニークパス生成
‘ ——————————————————————
Function GetUniqueTempPath(prefix)
Dim fso, tempFolder, shell, procID
Set fso = CreateObject(“Scripting.FileSystemObject”)
Set shell = CreateObject(“WScript.Shell”)

‘ プロセスIDを取得し、ユニーク性のベースにする
procID = shell.ExpandEnvironmentStrings(“%PROCESSOR_IDENTIFIER%”)

‘ 擬似乱数によるユニーク生成
Randomize
Dim salt: salt = Hex(Int((999999 – 100000 + 1) Rnd + 100000))

‘ 一時フォルダのパス確定
GetUniqueTempPath = fso.BuildPath(fso.GetSpecialFolder(2), _
prefix & “_” & procID & “_” & salt & “.tmp”)

‘ オブジェクトの早期解放
Set fso = Nothing
Set shell = Nothing
End Function

2. 競合回避型セーフ・ファイルアクセス

一時ファイルを確保する際、重要なのは「作成と書き込みをアトミックに行う」ことだ。`FileSystemObject` の `CreateTextFile` には第2引数(Overwrite)があるが、これを `False` に設定することで、ファイルが存在した場合にエラーを投げる挙動を強制できる。これこそが、競合を検知する最良のハンドリングだ。

実装:堅牢なファイル管理クラス

‘ ——————————————————————
‘ @Class: TempFileManager
‘ @Desc: ファイルのライフサイクル管理と強制削除の保証
‘ ——————————————————————
Class TempFileManager
Private m_FilePath

Public Property Let FilePath(val): m_FilePath = val: End Property

‘ ファイル作成(既存時はエラーを補足しリトライ)
Public Function CreateSafeFile()
Dim fso: Set fso = CreateObject(“Scripting.FileSystemObject”)
‘ 第2引数 False により、存在時はエラー発生
On Error Resume Next
Set CreateSafeFile = fso.CreateTextFile(m_FilePath, False)
If Err.Number <> 0 Then
Err.Raise 513, “TempFileManager”, “ファイル競合が発生しました: ” & m_FilePath
End If
On Error Goto 0
Set fso = Nothing
End Function

‘ 確実に削除する(プロセス終了時を想定)
Public Sub Destroy()
Dim fso: Set fso = CreateObject(“Scripting.FileSystemObject”)
If fso.FileExists(m_FilePath) Then
fso.DeleteFile m_FilePath, True
End If
Set fso = Nothing
End Sub
End Class

3. シニアエンジニアのための極限の知見

このコードを使用する際、君たちが意識すべき「極限の最適化」が3つある。

1. オブジェクトのライフサイクル管理:
VBScriptのガベージコレクションは頼りにならない。`Set obj = Nothing` を怠ることは、長期間稼働するタスクスケジューラ環境では「メモリリークの温床」となる。必ず `Finally` ブロック(VBScriptには存在しないため、サブルーチン終了直前)で明示的に解放せよ。
2. `On Error Resume Next` の正しい呪い:
エラーハンドリングを怠るな。エラーを握りつぶすのではなく、`Err.Number` を評価し、リトライ回数を制限して適切に終了させること。無限ループはシステムをハングアップさせる。
3. IOパフォーマンスへの配慮:
一時ファイルは `C:\Windows\Temp` ではなく、各ユーザーの `%TEMP%` 領域に出力せよ。権限問題による競合は、設定ミスではなく設計ミスである。

結論

VBScriptは、正しく制御すれば、現代の複雑なフレームワークよりも高速かつ安定して動作する。一時ファイルの管理は、システム全体の「衛生状態」を左右する。

「動くコード」を書くのはジュニアでもできる。「どんな過酷なマルチタスク環境でも、競合を予測し、メモリをクリーンに保ち、最後にはゴミを残さないコード」を書くこと。それこそが、我々アーキテクトに求められる美学である。

コードを信じるな。実行環境の挙動を信じろ。健闘を祈る。

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