こんにちは!現場でバリバリ自動化を進めていると、こんな壁にぶつかったことはありませんか?
「VBScriptでファイルの読み書き自動化を作ったはいいものの、対象のExcelファイルを誰かが開いていたせいで、スクリプトが突然『書き込みできません』エラー(実行時エラー)で強制終了してしまう……」
せっかく組んだ自動化バッチが、人の手によるファイルの閉じ忘れ一発で止まってしまうのは、エンジニアとして何としても避けたいところですよね。
今回は、FSO(ファイルシステムオブジェクト)の奥義である `OpenAsTextStream` メソッドの例外処理(エラートラップ)を利用して、ファイルが「他プロセスにガッツリ掴まれている(排他ロックされている)」かどうかをスマートに判定する極限のテクニックを伝授します。
ここをクリアすれば、あなたのVBScriptスキルは間違いなくワンランク上のステージに到達しますよ。一緒に本質をマスターしていきましょう!
—
なぜ「ファイルをいきなり開く」とスクリプトが死ぬのか?
Windowsの世界では、あるアプリケーション(例えばExcel)がファイルを開いている時、そのファイルには「排他ロック(Exclusive Lock)」という保護がかかります。他のプログラムが勝手に中身を書き換えてデータが破損するのを防ぐためです。
ここで、VBScriptの通常の思考回路のまま、次のようなコードを書いたとします。
Dim fso, file
Set fso = CreateObject(“Scripting.FileSystemObject”)
‘ 誰かが開いているファイルを容赦なく開こうとする
Set file = fso.OpenAsTextStream(“C:\data\report.xlsx”, 2) ‘ 2 = ForWriting
もし `report.xlsx` を誰かが開いていた場合、この瞬間、VBScriptは「エラー番号 70: 書き込み権限がありません (Permission denied)」を放ち、容赦なくスクリプト全体をクラッシュさせます。
これを防ぐためには、「開けるかどうか、恐る恐る事前にドアノックしてみる」というアプローチが必要になります。それが今回紹介する 例外処理によるロック検知 です。
—
核心:`On Error Resume Next` と `OpenAsTextStream` のコンボ
VBScriptには、エラーが発生してもスクリプトを止めずに続行させる魔法の呪文 `On Error Resume Next` があります。これを利用して、「ファイルを開こうとしてエラーが出たら、『あ、今使われてるな』と判断する」というロジックを組み立てます。
まずは、実務でそのままコピペして使える堅牢な関数を見てみましょう。
実用サンプルコード:ファイル使用中判定関数
Option Explicit
Dim targetPath
targetPath = “C:\data\sample.txt” ‘ 判定したいファイルのパス
If IsFileLocked(targetPath) Then
WScript.Echo “【警告】ファイルは現在、他のアプリ(Excel等)で使用されています。”
‘ ここにスキップ処理やリトライ処理を書く
Else
WScript.Echo “【OK】ファイルは安全に操作可能です。”
‘ ここに本来のファイル処理を書く
End If
‘ =================================================================
‘ 関数名: IsFileLocked
‘ 概要: 指定したファイルが他プロセスにロックされているか判定する
‘ 引数:
‘ strFilePath – 検査するファイルのフルパス
‘ 戻り値:
‘ Boolean – True: ロックされている / False: 空き状態
‘ =================================================================
Function IsFileLocked(strFilePath)
Dim fso, ts
Set fso = CreateObject(“Scripting.FileSystemObject”)
‘ ファイルが存在しない場合はロックされていないとみなす(必要に応じて調整)
If Not fso.FileExists(strFilePath) Then
IsFileLocked = False
Exit Function
End If
‘ 【重要】エラーが発生してもスクリプトを止めずに次の行へ進む
On Error Resume Next
‘ あえて「書き込みモード(ForWriting = 2)」でファイルを開いてみる
‘ ロックされていればここで必ずエラーが発生する
Set ts = fso.OpenAsTextStream(strFilePath, 2)
‘ エラー番号をチェック (Err.Number <> 0 ならばエラー発生 = ロック中)
If Err.Number <> 0 Then
IsFileLocked = True ‘ ロックされている!
Err.Clear ‘ エラー情報をクリア(これ超重要!)
Else
IsFileLocked = False ‘ 空いている!
ts.Close ‘ 開けちゃったのでちゃんと閉じる(リソースリーク防止)
End If
‘ エラー監視を通常モードに戻す
On Error GoTo 0
Set ts = Nothing
Set fso = Nothing
End Function
—
コードの深い解説:なぜこの書き方が「プロの技」なのか?
ただ動くだけのコードなら誰でも書けます。しかし、長期間稼働する自動化スクリプトを作るためには、オブジェクトのライフサイクルとメモリ管理に配慮しなければなりません。ここでは3つの重要なポイントを解説します。
1. なぜ「読み込み」ではなく「書き込みモード(2)」で開くのか?
`OpenAsTextStream` の第二引数には、以下の3つを指定できます。
- `1` : ForReading(読み込み専用)
- `2` : ForWriting(書き込み専用)
- `8` : ForAppending(追加書き込み)
多くのファイルは、Excelなどで開かれていても「読み取り専用」であれば他のプログラムから開けることがあります。しかし、私たちが自動化スクリプトで本当に防ぎたいのは「書き込もうとして弾かれるエラー」です。そのため、あえて最初から書き込みモード(`2`)でアプローチし、排他ロックを厳密に検知しているのです。
2. `Err.Clear` の絶対的な必要性
VBScriptの `Err` オブジェクトは、一度エラーが発生すると、明示的にクリアするまでエラー情報を保持し続けます。
もし `Err.Clear` を書き忘れると、関数を複数回呼び出した際に「前回の残像エラー」を拾ってしまい、実際はファイルが空いているのに「ロックされている」と誤判定する大バグの原因になります。エラーをキャッチしたら、速やかに `Err.Clear` でお掃除するのが鉄則です。
3. 開けた場合の `ts.Close` とメモリ解放
もしファイルが空いていて、無事に `OpenAsTextStream` が成功した場合、ファイルストリーム(`ts`)がメモリ上に開いた状態になります。これをそのまま放置すると、ファイルハンドルが解放されず、次に自分で書き込もうとした時に「リソース不足」や「アクセス拒否」を引き起こします。
「開いたら必ず閉じる(`ts.Close`)」、そしてオブジェクトは最後に `Nothing` を代入してメモリをキレイに掃除する。この美学を忘れないでください。
—
現場でありがち!陥りやすい罠と注意点
初心者がこのロジックを実務に組み込む際、よくハマるポイントを先回りして共有しておきます。
- ネットワークドライブ上のファイル判定
社内の共有サーバー(NASやSharePointなど)にあるファイルは、ネットワークの遅延や、OSのファイルキャッシュのタイムラグにより、「すでにExcelを閉じたのに、数秒間はロック状態が解除されない」という現象が起きることがあります。ファイル閉じる→即スクリプト実行、というタイト-な設計にする場合は、判定の前に `WScript.Sleep 1000`(1秒待機)などを挟むと、誤検知を防ぐ頑健なシステムになります。
- ファイルが存在しない場合のエラー
指定したパスにそもそもファイルがない場合、`OpenAsTextStream` は別のエラー(ファイルが見つかりません)を発生させます。サンプルコードのように、事前に `fso.FileExists` で存在チェックを挟むか、エラー番号(`Err.Number`)の中身を精査する分岐を入れると、さらに実用性が増します。
—
まとめ:ここをクリアすればVBScriptの基本はバッチリ!
今回は、FSOの `OpenAsTextStream` を使ったファイル排他ロックの検知ロジックについて解説しました。
- `On Error Resume Next` でエラーをトラップする
- あえて 書き込みモード(2) で開いてみる
- `Err.Number` でロックの有無を判定し、`Err.Clear` を忘れない
- 成功した場合は必ず `ts.Close` で閉じる
この4つのステップを自分のものにできたなら、あなたはもう「マクロの記録を貼り付けるだけの初学者」ではありません。現場のトラブルを華麗に回避できる、信頼性の高い自動化エンジニアです。
日々のバッチ処理の安定性向上に、ぜひこの知見を役立ててくださいね。それでは、快適なVBScriptライフを!
