【パス解析の極意】GetAbsolutePathNameとGetParentFolderNameでVBScriptのファイル操作を「鉄壁」にする方法
開発プロジェクトで自動化スクリプトを組む際、最も多くのバグを生む温床が「ファイルパスの解体と正規化」の甘さにある。
`C:\data\input.csv` のような綺麗なフルパスばかりが飛んでくる現場なら苦労はしない。しかし、実務の現場では以下のようなカオスなパスが平然と現れる。
- カレントディレクトリからの相対パス(`.\data\..\output\result.txt`)
- スラッシュ(`/`)とバックスラッシュ(`\`)が混在したネットワークパス
- 拡張子のないファイルや、多重にネストされたフォルダ構造
「とりあえず `Split` 関数で `\` ごとに分割して配列の末尾を取ればいいや」などと実装しているとしたら、それは今すぐやめるべきだ。環境やパスの揺れによって一撃で破綻する。
今回は、ファイルシステムオブジェクト(FSO)が持つ本質的なパス解析メソッド、`GetAbsolutePathName` と `GetParentFolderName`(および関連メソッド)を駆使し、環境に依存せず、バグの起きない堅牢なパス操作の極意を伝授する。
—
1. なぜ「文字列操作」でのパス解析は失敗するのか?
多くの初学者が、ファイルパスからファイル名や親フォルダを得るために以下のようなコードを書く。
‘ 【アンチパターン】絶対に真似してはいけない文字列切り出し
Dim fullPath, parts, fileName
fullPath = “C:\WorkFolder\SubFolder\data.txt”
parts = Split(fullPath, “\”)
fileName = parts(UBound(parts)) ‘ 運良く “data.txt” が取れるが…
この手法が実務で通用しない理由は明白だ。
1. 相対パスや不完全なパスへの耐性ゼロ:`..\..\config.ini` のようなパスが渡された途端、ロジックが崩壊する。
2. スラッシュの混入:Web経由や一部のAPIから取得したパスに `/` が混ざっているだけで、配列のインデックスが狂う。
3. ドライブ直下やUNCパスの考慮漏れ:`C:\` や `\\server\share\` を対象にした際、境界値でエラーを起こす。
VBScriptにおけるパス解析は、文字列操作ではなく「ファイルシステム上の位置計算」として捉えなければならない。ここでFSO(`Scripting.FileSystemObject`)の出番となる。
—
2. FSOパス解析メソッドの真価と使い分け
FSOには、パスを安全に料理するための専用メソッドが用意されている。これらを適切に組み合わせることで、いかなる入力値も完全にコントロールできる。
① `GetAbsolutePathName` (正規化の要)
曖昧な相対パスや、`..` や `.` を含んだ汚れたパスを、OSが解釈できる絶対パスのフル文字列へと変換する。さらに、スラッシュの正規化やドライブ名の補完も同時に行ってくれる。
② `GetParentFolderName` (階層の剥離)
指定したパスから「一番下の階層(ファイル名または最下層フォルダ名)」を削ぎ落とし、その親フォルダのパスを返す。
③ 補助メソッド群
- `GetFileName`:パスからファイル名(拡張子含む)を抽出する。
- `GetExtensionName`:拡張子のみを抽出する(ドットは含めない)。
- `GetBaseName`:拡張子を除いたファイル名を抽出する。
これらは文字列ベースで動作するため、実際のファイルやフォルダがディスク上に存在していなくても機能するという極めて強力な特性を持っている。
—
3. 【プロダクションコード】堅牢なパス解析・正規化エンジン
実務の現場でそのまま組み込める、保守性の高いVBScriptのサンプルコードを提示する。
単にメソッドを呼ぶだけでなく、エラーハンドリングと、各種情報の構造化(ログ出力などへの応用)を意識した設計にしている。
Option Explicit
‘ メイン処理の実行
Call AnalyzeFilePath(“.\input\..\data\sample_report.CSV”)
Call AnalyzeFilePath(“\\192.168.1.50\share\docs\2023\10\data.tar.gz”)
Call AnalyzeFilePath(“C:\SingleFile.txt”)
Sub AnalyzeFilePath(rawPath)
Dim fso
Set fso = CreateObject(“Scripting.FileSystemObject”)
WScript.Echo “————————————————–”
WScript.Echo “【入力された生パス】: ” & rawPath
On Error Resume Next
‘ 1. 絶対パスへの正規化(環境依存や相対パスの解決)
Dim absPath
absPath = fso.GetAbsolutePathName(rawPath)
If Err.Number <> 0 Then
WScript.Echo “[ERROR] パスの正規化に失敗しました: ” & Err.Description
Err.Clear
Set fso = Nothing
Exit Sub
End If
‘ 2. 各要素の抽出
Dim parentDir, fileName, baseName, extName
parentDir = fso.GetParentFolderName(absPath)
fileName = fso.GetFileName(absPath)
baseName = fso.GetBaseName(absPath)
extName = fso.GetExtensionName(absPath)
On Error GoTo 0
‘ 3. 解析結果の出力
WScript.Echo ” -> 絶対パス(正規化): ” & absPath
WScript.Echo ” -> 親フォルダ : ” & parentDir
WScript.Echo ” -> ファイル名 : ” & fileName
WScript.Echo ” -> ベース名 : ” & baseName
WScript.Echo ” -> 拡張子 : ” & extName
Set fso = Nothing
End Sub
このコードのアーキテクチャ上のポイント
- `On Error Resume Next` の局所的使用: 特殊なネットワークパスや文字コードの問題でFSOが例外を吐く稀なケースに備え、プロセスがクラッシュするのを防ぐ防護壁を張っている。
- ディスクアクセスを伴わない: これらのメソッド群は文字列演算ベースで最適化されているため、I/Oボトルネックが発生せず、高速に動作する。
—
4. 業務自動化における実務的な注意点
チーフアーキテクトとして、現場でこのコードを運用する際の「罠」をいくつか警告しておこう。
1. UNCパス(ネットワーク共有)の挙動
`\\server\share\folder` に対して `GetParentFolderName` を繰り返していくと、最終的に `\\server\share` になり、さらに進めると空文字 `””` が返る。ルート階層の判定を入れる場合は、戻り値が空になっていないかのガード節が必須となる。
2. 大文字・小文字の正規化
`GetAbsolutePathName` はパスの構造を整えてくれるが、拡張子のケース(`.CSV` と `.csv`)までは強制的に統一してくれない。比較やDB連携を行う際は、必要に応じて `LCase()` や `UCase()` を併用すること。
3. COMオブジェクトの解放ライフサイクル
スクリプトが肥大化するにつれ、`CreateObject(“Scripting.FileSystemObject”)` をあちこちに乱立させる開発者がいる。メモリリークや無駄なインスタンス生成を避けるため、FSOはスクリプト内で可能な限り共通のインスタンスを使い回す設計にすべきだ。
—
総括
VBScriptにおけるFSOのパス解析は、地味ながら自動化ツールの品質を決定づける「土台」である。
「動けばいいや」の文字列操作から脱却し、`GetAbsolutePathName` と `GetParentFolderName` を軸としたFSOのセマンティクスを理解・実装することで、あなたの書くスクリプトは環境の変化や予期せぬ入力値に対しても揺るぎない、「プロダクション品質の堅牢さ」を手に入れる。
プロのエンジニアとしての誇りを持ち、細部の設計にこそこだわりを持ってコードを書き上げてほしい。
