【実務・中級編】【排他ロック検知】OpenAsTextStreamメソッドの例外処理を利用した「他プロセス使用中」ファイルの判定ロジック – VBScript (Visual Basic Scripting Edition)解析バイブル

スポンサーリンク

【排他ロック検知】OpenAsTextStreamメソッドの例外処理を利用した「他プロセス使用中」ファイルの判定ロジック

業務自動化の現場において、VBScriptによるファイル操作は今なお強力な武器だ。しかし、多くの開発者が「他プロセスが掴んでいるファイルにアクセスし、スクリプトが突然死する」という壁にぶつかっている。

特に、Excelや基幹システムが排他ロック(Exclusive Lock)をかけているファイルを無防備に読み込もうとすれば、Runtime Errorが容赦なくスクリプトを強制終了させる。タスクスケジューラで無人実行しているバッチ処理であれば、これは致命傷だ。

今回は、FileSystemObject(FSO)の `OpenAsTextStream` メソッドが持つ挙動と、VBScriptのプリミティブなエラーハンドリング(`On Error`)を極限まで組み合わせた、「実戦で絶対に落ちない排他ロック検知ロジック」を伝授する。

—

なぜ「事前の存在確認」では意味がないのか?

素人設計のスクリプトによありがちなアンチパターンがこれだ。

‘ 【NGパターン】これでは排他ロックは防げない
Set fso = CreateObject(“Scripting.FileSystemObject”)
If fso.FileExists(targetPath) Then
‘ この瞬間にも、別プロセスがファイルを開く可能性がある(競合状態)
Set file = fso.GetFile(targetPath)
Set stream = file.OpenAsTextStream(1, 0) ‘ ここで落ちる
End If

`FileExists` や `GetFile` は、あくまで「ファイルシステム上にそのパスが存在するか」を確認しているに過ぎない。ファイルが「OSレベルで他のプロセスに占有されているか(ロックされているか)」を判定することはできないのだ。さらに言えば、存在確認からファイルを開くまでのわずかな隙間に別プロセスが介入する「TOCTOU(Time-of-check to time-of-use)競合」のリスクすら存在する。

唯一の真実:「開いてみなければわからない」

OSのファイルロック機構において、安全にファイルの占有状態を知る唯一の方法は、「実際に排他制御を考慮したオープンを試み、その成否を例外として捉えること」である。これ以外に確実な方法はない。

—

OpenAsTextStreamメソッドによる例外トラップ設計

ここで主役となるのが、`File` オブジェクトの `OpenAsTextStream` メソッドだ。

object.OpenAsTextStream([iomode, [format]])

  • iomode: `1` (ForReading), `2` (ForWriting), `8` (ForAppending)
  • format: `0` (ASCII), `-1` (Unicode), `-2` (システムデフォルト)

このメソッドは、ファイルが他のプロセスによって「読み取り不可(あるいは書き込み不可)」の状態でロックされている場合、VBScriptのランタイムエラー(エラー番号:`70` 「書き込みできません」または類似の権限エラー)を発生させる。

この仕様を逆手に取り、「あえてエラーを発生させ、そのトラップによって使用中判定を下す」のが本アーキテクチャの核心である。

—

プロダクションコード:堅牢な排他ロック検知ファンクション

現場でそのままコピペして利用できる、モジュール化された実用関数を提示する。エラー番号の捕捉、オブジェクトの確実な解放(メモリリーク防止)、厳密な型・状態管理を実装している。

Option Explicit

Dim targetFile
targetFile = “C:\Data\SharedReport.xlsx” ‘ 判定対象のファイルパス

If IsFileLocked(targetFile) Then
WScript.Echo “【警告】ファイルは現在、他のプロセスで使用されています: ” & targetFile
‘ ここにリトライ処理や処理スキップのロジックを記述
Else
WScript.Echo “【成功】ファイルは安全にアクセス可能です。”
‘ ここに本来のファイル処理を記述
End If

‘ ==============================================================================
‘ 関数名: IsFileLocked
‘ 概要: 指定されたファイルが他プロセスによって排他ロックされているかを判定する
‘ 引数: ByVal strFilePath (String) – 判定対象のファイルパス
‘ 戻り値: Boolean – ロックされている場合は True、それ以外は False
‘ ==============================================================================
Function IsFileLocked(ByVal strFilePath)
Dim fso, oFile, oStream
Dim lngErrNumber

‘ デフォルトは「ロックされていない(安全)」と仮定
IsFileLocked = False

Set fso = CreateObject(“Scripting.FileSystemObject”)

‘ ファイルが存在しない場合は、ロック以前の問題なのでFalseを返すか、
‘ あるいは別ハンドリングを行う(今回は安全側に倒してFalse)
If Not fso.FileExists(strFilePath) Then
Set fso = Nothing
Exit Function
End If

‘ エラーハンドリングの有効化
On Error Resume Next

Set oFile = fso.GetFile(strFilePath)
‘ 読み込みモード(ForReading=1)でストリームを開くを試行
‘ ※他プロセスが排他書き込みをしている場合、ここでエラー70等が発生する
Set oStream = oFile.OpenAsTextStream(1, 0)

lngErrNumber = Err.Number

‘ エラーが発生した場合のクリーンアップと判定
If lngErrNumber <> 0 Then
‘ エラー番号 70 (Permission Denied) などを想定
IsFileLocked = True
Err.Clear
End If

‘ オブジェクトのライフサイクル管理(確実に閉じて解放する)
If Not oStream Is Nothing Then
oStream.Close
Set oStream = Nothing
End If

Set oFile = Nothing
Set fso = Nothing

‘ エラーハンドリングを通常に戻す(重要:スコープ外へのエラー伝播を防ぐ)
On Error GoTo 0
End Function

—

チーフアーキテクトが教える実装上の極意・注意点

このコードをプロダクション環境に投入するにあたり、以下のポイントを遵守してほしい。

1. `On Error Resume Next` のスコープと即時リセット

VBScriptの最大の悪習は、エラーハンドリングをグローバルに放置し、想定外のバグを隠蔽してしまうことだ。今回の関数内でも `On Error Resume Next` を使用しているが、関数を抜ける前、あるいは判定直後に必ず `On Error GoTo 0` で無効化している。これにより、メインルーチン側のデバッグ性を完全に保護している。

2. ストリームのクローズとオブジェクト破棄

「開こうとしてエラーになった」場合でも、VBScriptの内部環境によっては中途半端なオブジェクト参照が残ることがある。`oStream.Close` はエラー時に失敗する可能性があるため、オブジェクトの破棄(`Set … = Nothing`)を徹底し、COMコンポーネントのメモリリーク(VBScriptランタイムにおける致命的なパフォーマンス低下の原因)を完全に阻止する構造にしている。

3. Excel等の「読み取り専用」で開かれている場合の挙動

Excelがファイルを開く際、デフォルトでは排他ロックをかけるが、ユーザーが「読み取り専用」で開いている場合、他のプロセスからの読み取りアクセス(`ForReading`)は許可されることが多い。
もし「書き込み競合」を防ぎたいのであれば、`OpenAsTextStream` の引数を `2` (ForWriting) に変更することで、「誰にも編集として掴まれていないか」を厳密に検知することが可能だ。業務要件(読むだけなのか、上書き保存したいのか)に合わせて `iomode` を適切に設計してほしい。

—

総括

VBScriptはレガシーな言語と揶揄されることもあるが、OSのプリミティブなAPIやCOMコンポーネント(FSO)の挙動を熟知していれば、ここまで堅牢で実用的な自動化ツールを組み上げることができる。

「エラーが起きる前に防ぐ」のではなく、「起きうる例外をエレガントにハンドリングし、システムを絶対に落とさない」こと。これが、プロフェッショナルな業務自動化エンジニアの código(コード)である。現場の安定稼働のために、ぜひこの知見を組み込んでほしい。

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