【実務・中級編】【初心者向け】Drive.FileSystemプロパティによるフォーマット形式(NTFS/FAT32等)の自動判別と処理の安全分岐 – VBScript (Visual Basic Scripting Edition)解析バイブル

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

【極限の知見】VBScriptで「現場で死なない」自動化ツールを作る:Drive.FileSystemによるファイルシステム判別と堅牢な分岐設計

業務自動化の現場において、「自分のPCでは動いた」という言葉ほど無責任なものはない。

君が書いたVBScriptが、開発環境のNTFSフォーマットされたローカルHDDでは完璧に動作したとしても、それが現場の「FAT32形式のUSBメモリ」や「権限が厳格に制限されたネットワークドライブ」に投入された瞬間、そのツールは牙を剥き、エラーを吐き出し、最悪の場合はデータの破損を招く。

自動化エンジニアの真価は、ハッピーパス(正常系)を書く能力ではなく、「環境の差異という地雷」を事前に察知し、それを回避するロジックを設計に組み込む能力にある。

本稿では、FileSystemObject (FSO) を用いて対象ドライブのファイルシステムを判別し、4GBの壁やアクセス権限の差異を乗り越えるための「プロフェッショナルな設計思想」を伝授する。

1. なぜ「単なるコピー」では足りないのか?

多くの初心者は、ファイルを移動・コピーする際、以下のようなコードを書く。

' 典型的な「現場で事故を起こす」コード
Set fso = CreateObject("Scripting.FileSystemObject")
fso.CopyFile "C:\Source\LargeData.zip", "E:\Backup\LargeData.zip"

これでは、`E:` ドライブが FAT32 だった場合、ファイルサイズが4GBを超えた瞬間に実行時エラーで停止する。あるいは、書き込み権限のないディレクトリに対して実行し、エラーハンドリングも不十分なためにプロセスが中途半端な状態で終了し、不完全なファイルが残る。

これらはすべて、「実行環境の物理的特性(ファイルシステム種別)」を無視した設計に起因する。

考慮すべき2つの致命的な差異

1. ファイルサイズ制限(FAT32の壁):
FAT32形式のドライブは、単一ファイルにつき 4GB (4,294,967,295バイト) を超えるファイルを扱うことができない。現代のバックアップデータやログファイルにおいて、これは極めて現実的な制約である。
2. セキュリティモデル(NTFS vs FAT):
NTFSは高度なアクセス制御リスト (ACL) を持つが、FAT系は持たない。権限チェックが必要な処理において、この差異を無視すると、管理者権限が必要な操作でスクリプトが沈黙する。

2. 核心技術:`Drive.FileSystem` プロパティの掌握

FSOの `Drive` オブジェクトには、そのドライブのフォーマット形式を返す `FileSystem` プロパティが存在する。これを利用することで、処理を開始する前に「このドライブで何が可能か」を判定できる。

判別される値は、主に以下の通りだ:

  • `”NTFS”`
  • `”FAT”`
  • `”exFAT”`

これらを、列挙型(Enum)のように定数として定義し、ロジックの分岐に使用するのがプロの書き方である。

3. 実践:堅牢なファイル転送エンジンの実装例

以下に、ドライブのフォーマットを事前にチェックし、4GB制限を回避するための安全な分岐を持つ、プロダクションレベルのコードを示す。

' ==========================================================================
' Script Name: RobustFileTransfer.vbs
' Description: ファイルシステムの種別を判別し、容量制限を回避する安全なコピー処理
' Author: Legendary Chief Architect
' ==========================================================================

Option Explicit

' --- 定数定義 (マジックナンバーを排除し、保守性を高める) ---
Const FS_NTFS = "NTFS"
Const FS_FAT  = "FAT"
Const FS_EXFAT = "exFAT"
Const MAX_FAT_FILE_SIZE = 4294967295 ' FAT32の限界値 (4GB - 1byte)

' --- メイン処理 ---
Sub Main()
    Dim fso, sourceFile, targetDrive, targetPath
    
    Set fso = CreateObject("Scripting.FileSystemObject")
    
    ' 設定値(本来は外部設定ファイルや引数から取得すべき)
    sourceFile = "C:\Work\BigData.zip" 
    targetDrive = "E:" ' 対象ドライブ
    targetPath = "E:\Backup\BigData.zip"

    ' 1. 事前バリデーション
    If Not fso.FileExists(sourceFile) Then
        WScript.Echo "Error: ソースファイルが存在しません。"
        WScript.Quit 1
    End If

    ' 2. ドライブの存在とファイルシステムの判別
    Dim fsType
    fsType = GetDriveFileSystem(fso, targetDrive)

    If fsType = "Unknown" Then
        WScript.Echo "Error: 対象ドライブが見つからないか、アクセスできません。"
        WScript.Quit 1
    End If

    WScript.Echo "Detected FileSystem: " & fsType

    ' 3. 安全な処理分岐 (Safety Branching)
    On Error Resume Next ' 実行時エラーによる即時停止を防ぐ
    
    Dim fileSize
    fileSize = fso.GetFile(sourceFile).Size

    Select Case fsType
        Case FS_NTFS, FS_EXFAT
            ' NTFSおよびexFATは4GB制限を気にせずコピー可能
            ExecuteCopy fso, sourceFile, targetPath
            
        Case FS_FAT
            ' FAT32の場合、サイズチェックが必須
            If fileSize > MAX_FAT_FILE_SIZE Then
                WScript.Echo "Critical Error: FAT32形式のドライブに4GBを超えるファイルをコピーすることはできません。"
                WScript.Echo "Source Size: " & FormatBytes(fileSize)
                WScript.Quit 1
            Else
                ExecuteCopy fso, sourceFile, targetPath
            End If
            
        Case Else
            WScript.Echo "Error: 未知のファイルシステムです。処理を中断します。"
            WScript.Quit 1
    End Select

    If Err.Number <> 0 Then
        WScript.Echo "Runtime Error: " & Err.Description
        WScript.Quit 1
    End If
    On Error GoTo 0

    WScript.Echo "Success: ファイルの転送が完了しました。"
End Sub

' --- 関数: ドライブのファイルシステム種別を取得 ---
Function GetDriveFileSystem(fso, driveLetter)
    On Error Resume Next
    Dim drive
    Set drive = fso.GetDrive(driveLetter)
    
    If Err.Number <> 0 Then
        GetDriveFileSystem = "Unknown"
    Else
        ' Drive.FileSystem プロパティを返却
        GetDriveFileSystem = UCase(drive.FileSystem)
    End If
    On Error GoTo 0
End Function

' --- サブルーチン: コピー実行部 ---
Sub ExecuteCopy(fso, src, dest)
    ' ディレクトリの存在確認と作成(必要に応じて拡張)
    Dim destDir
    destDir = fso.GetParentFolderName(dest)
    If Not fso.FolderExists(destDir) Then
        fso.CreateFolder(destDir)
    End If
    
    ' コピー実行
    fso.CopyFile src, dest, True
End Sub

' --- 関数: バイト数を読みやすい形式に変換 (デバッグ用) ---
Function FormatBytes(bytes)
    Dim units, unitIdx
    units = Array("B", "KB", "MB", "GB", "TB")
    unitIdx = 0
    Do While bytes >= 1024 And unitIdx < 4
        bytes = bytes / 1024
        unitIdx = unitIdx + 1
    Loop
    FormatBytes = Round(bytes, 2) & " " & units(unitIdx)
End Function

' 実行開始
Main

4. アーキテクトの視点:設計のポイント

このコードが、なぜ「単なるスクリプト」ではなく「プロダクションコード」と呼べるのか。その設計思想を解説する。

① エラーハンドリングの階層化

単に `On Error Resume Next` を冒頭に書くのは素人の仕事だ。それはエラーを「無視」しているだけで、解決していない。
私の設計では、「ドライブの存在確認」「ファイルシステムの判別」「コピー実行」の各フェーズで、エラーの性質(存在しないのか、仕様制限なのか、実行時エラーなのか)を切り分けている。

② 定数化による保守性の担保

`”NTFS”` や `”FAT”` といった文字列を直接ロジック内に書き込む(マジックストリング)ことは厳禁だ。
将来、新しいファイルシステムが登場した際、あるいは判定ロジックを変更したい際、定数定義を一箇所書き換えるだけで済むように設計しておく。これが「保守性の高いコード」の第一歩だ。

③ 失敗を「予測」するロジック

`Select Case` 文を用いた分岐は、単なる条件分岐ではない。これは「リスクマネジメント」だ。
「FAT32ならサイズをチェックする」というロジックを入れることで、エラーが発生してから対処するのではなく、エラーが発生する前にユーザーに通知し、システムを安全に停止させている。

5. まとめ:プロフェッショナルへの道

VBScriptは古い言語かもしれない。しかし、そのオブジェクトモデルを完全に掌握し、環境の物理的制約を考慮したコードを書けるエンジニアは、今なお現場で極めて高い価値を持つ。

次に君がスクリプトを書くときは、自分に問いかけてほしい。
「このスクリプトは、想定外のUSBメモリに刺されたとき、どう振る舞うか?」

その問いへの答えが、君のコードに「堅牢性」という魂を吹き込むのだ。

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