【実務・中級編】【実務中級者向け】FSOファイルコピー実行前に空き容量(AvailableSpace)をチェックするガードロジックの実装 – VBScript (Visual Basic Scripting Edition)解析バイブル

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

「ただのコピー」で終わらせるな。VBScriptにおけるファイルコピーの「事前防衛ロジック」を極める

業務自動化の世界において、最も初歩的でありながら、最も多くのエンジニアが「現場の混乱」を招くミスを犯す。それが「容量を考慮しないファイル転送」だ。

数GB、あるいは数TBに及ぶデータのバックアップや、大量のログファイルを共有サーバへ転送するスクリプトを書いていないだろうか? もし、転送先のディスク容量が不足していた場合、あなたのスクリプトはどう動く?

「途中でエラーが出て止まる」?
甘い。

エラーが発生した瞬間、転送先には「中途半端に書き込まれた壊れたファイル」が残り、システムは不整合を起こし、復旧のためにエンジニアが深夜に呼び出されることになる。これは「自動化」ではなく「障害の自動生成」だ。

今日は、プロフェッショナルとして、ファイルコピーを実行する前に「転送先の空き容量(AvailableSpace)を検証し、リスクを事前に排除するガードロジック」の実装術を伝授する。

1. なぜ「単純な比較」では不十分なのか

初心者はこう書く。
`If FileSize < Drive.FreeSpace Then CopyFile` これでは実務では通用しない。アーキテクトの視点から見れば、ここには2つの致命的な欠陥がある。

欠陥①:レースコンディション(競合状態)への無防備

ファイルシステムは動的な生き物だ。あなたのスクリプトが「空き容量はある」と判定した直後、別のプロセス(Windows Updateやログ出力など)がディスクを消費する可能性がある。判定と実行の間にわずかな「隙」がある限り、容量不足の確率はゼロにはならない。

欠陥②:安全マージン(Buffer)の欠如

「必要なサイズ」と「空き容量」がぴったり同じ場合、転送中にファイルシステムのメタデータ更新や、一時的なキャッシュ領域の消費で、確実にエラーが発生する。

設計指針:
「空き容量 > 必要ファイルサイズ + 安全マージン」という評価式を、堅牢な例外処理と共に実装しなければならない。

2. プロダクション品質のガードロジック実装

以下に示すのは、単なる判定関数ではない。エラーハンドリング、単位変換、そして「なぜ失敗したのか」を呼び出し元に伝えるための設計思想を盛り込んだコードだ。

'**
' Module: FileTransferGuard
' Description: ファイルコピー実行前のディスク容量チェックおよび安全な転送
' Author: Chief Architect
'**

Option Explicit

' 定数定義:実務における「安全マージン」の設計
' ここでは、予期せぬ書き込みに備え、常に 500MB のバッファを確保する設計とする
Const SAFETY_MARGIN_BYTES = 524288000 ' 500 * 1024 * 1024

Dim FSO
Set FSO = CreateObject("Scripting.FileSystemObject")

' --- メイン処理例 ---
Dim sourceFile, destFolder
sourceFile = "C:\Data\LargeBackup.zip"
destFolder = "D:\BackupTarget\"

' 実行判定
If CheckSpaceAndCopy(sourceFile, destFolder) Then
    WScript.Echo "SUCCESS: ファイル転送が正常に完了しました。"
Else
    WScript.Echo "FAILURE: ファイル転送に失敗しました。詳細はログを確認してください。"
    WScript.Quit 1
End If

'**
' Function: CheckSpaceAndCopy
' Purpose: 容量をチェックし、安全が確認できた場合のみコピーを実行する
' Returns: Boolean (成功ならTrue, 容量不足またはエラーならFalse)
'**
Function CheckSpaceAndCopy(strSource, strDestDir)
    On Error Resume Next
    Dim objFile, objDrive, lngRequiredSize, lngAvailableSpace
    Dim strDestDriveRoot

    ' 1. ソースファイルの存在確認
    If Not FSO.FileExists(strSource) Then
        WScript.Echo "[Error] ソースファイルが存在しません: " & strSource
        CheckSpaceAndCopy = False
        Exit Function
    End If

    ' 2. ファイルサイズと必要容量の計算
    Set objFile = FSO.GetFile(strSource)
    lngRequiredSize = objFile.Size
    
    ' 3. 転送先ドライブの特定
    ' GetDriveはパスを受け取ると、そのパスが属するドライブオブジェクトを返す
    strDestDriveRoot = FSO.GetDrive(strDestDir).DriveLetter & "\"
    Set objDrive = FSO.GetDrive(strDestDriveRoot)
    
    If Err.Number <> 0 Then
        WScript.Echo "[Error] 転送先ドライブの取得に失敗しました: " & Err.Description
        CheckSpaceAndCopy = False
        Exit Function
    End If

    ' 4. 空き容量の取得 (AvailableSpaceを使用)
    ' FreeSpaceではなくAvailableSpaceを使うのがプロの作法。
    ' AvailableSpaceはユーザーが利用可能な実際の空き容量を返す。
    lngAvailableSpace = objDrive.AvailableSpace

    ' 5. ガードロジック:容量判定 (必要サイズ + マージン < 空き容量)
    If (lngRequiredSize + SAFETY_MARGIN_BYTES) > lngAvailableSpace Then
        WScript.Echo "[Critical] 容量不足を検知しました。"
        WScript.Echo "   必要容量 (推定): " & FormatBytes(lngRequiredSize + SAFETY_MARGIN_BYTES)
        WScript.Echo "   現在の空き容量: " & FormatBytes(lngAvailableSpace)
        CheckSpaceAndCopy = False
        Exit Function
    End If

    ' 6. コピー実行
    ' ここまで到達したということは、安全が確認されている
    FSO.CopyFile strSource, strDestDir, True ' True = 上書き許可
    
    If Err.Number <> 0 Then
        WScript.Echo "[Error] コピー実行中に致命的なエラーが発生しました: " & Err.Description
        CheckSpaceAndCopy = False
    Else
        CheckSpaceAndCopy = True
    End If

    On Error GoTo 0
End Function

'**
' Function: FormatBytes
' Purpose: バイト単位の数値を人間が読みやすい形式(GB/MB)に変換する
'**
Function FormatBytes(lngBytes)
    Dim dblSize
    dblSize = CDbl(lngBytes)
    
    If dblSize >= 1073741824 Then ' GB
        FormatBytes = Round(dblSize / 1073741824, 2) & " GB"
    ElseIf dblSize >= 1048576 Then ' MB
        FormatBytes = Round(dblSize / 1048576, 2) & " MB"
    Else
        FormatBytes = Round(dblSize / 1024, 2) & " KB"
    End If
End Function

3. アーキテクトが教える、さらに踏み込んだ設計の勘所

上記のコードをベースに、実務レベルのツールへ昇華させるための「3つの極意」を伝えておく。

① AvailableSpace vs FreeSpace

VBScriptの `Drive` オブジェクトには `FreeSpace` と `AvailableSpace` が存在する。

  • `FreeSpace`: ディスク全体の空き領域。
  • `AvailableSpace`: 現在実行中のユーザーが利用可能な領域。(クォータ制限などが適用されている場合、こちらが正しい)

業務自動化においては、必ず `AvailableSpace` を使用せよ。

② データベースとの連携における「冪等性(べきとうせい)」

もしこのスクリプトを、転送完了後にDBへ「完了フラグ」を立てるようなワークフローの一部として組み込むなら、「失敗した時に中途半端なファイルが残っていないこと」を保証しなければならない。

理想的な設計は、以下のフローだ。
1. 容量チェック(Guard)
2. 一時ファイル名でコピー(例: `data.zip.tmp`)
3. コピー完了後、リネームして本来のファイル名にする
4. DBへステータスを書き込む

これにより、万が一の容量不足やネットワーク遮断が発生しても、不完全なファイルが「完成品」として誤認されるリスクをゼロにできる。

③ ログ出力の重要性

`WScript.Echo` はデバッグには良いが、運用フェーズではゴミだ。
実務用のツールを作るなら、判定結果(`lngAvailableSpace` や `lngRequiredSize` の実数値)を必ずテキストログ、あるいはイベントログへ記録せよ。後から「なぜあの時バックアップが走らなかったのか?」を調査する際、その数値こそが唯一の真実となる。

結論

「動けばいい」という考え方は、プログラミングには通用するが、エンジニアリングには通用しない。

容量チェックという一行のガードロジックを実装する。その背後にある「レースコンディションへの懸念」と「安全マージンの確保」という思考プロセスこそが、ジュニアとシニアを分かつ境界線である。

堅牢なコードを書け。システムに「予測不可能な挙動」を許すな。

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