【実務・中級編】【初心者向け】GetFileメソッドで取得できる「最終アクセス日時(DateLastAccessed)」と「最終更新日時」の差分と使い分け – VBScript (Visual Basic Scripting Edition)解析バイブル

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

タイムスタンプの罠を回避せよ:FSOにおける「更新日時」と「アクセス日時」の真実

業務自動化の世界において、ファイル操作は最も基本的でありながら、最も「設計の甘さ」が露呈しやすい領域だ。

多くの開発者が、File System Object (FSO) を使って「古いファイルを削除する」「特定の期間のログを抽出する」といったスクリプトを、リファレンス通りに、何も考えずに書き始める。しかし、その設計には致命的な欠陥が潜んでいることが多い。

特に、`DateLastModified`(最終更新日時)と `DateLastAccessed`(最終アクセス日時)の使い分けを誤ると、「必要なデータを誤って削除する」、あるいは「監査ログに虚偽の記録を残す」という、業務システムとしてあってはならない事態を招く。

今日は、プロフェッショナルとして、この「時間のプロパティ」をどう制御し、どう設計すべきかを伝授する。

1. 属性情報の正体:何が「変化」を意味するのか

FSOの `File` オブジェクトが提供する日時プロパティは、単なる数字ではない。それらはファイルに対する「操作の履歴」である。

DateLastModified(最終更新日時)

これは、「ファイルの中身(データ)が書き換えられた瞬間」を指す。
テキストファイルに一行追記した、Excelのセルを書き換えた、バイナリを更新した――これらがトリガーだ。業務ロジックにおいて、「いつデータが最新になったか」を知るための唯一の信頼できる指標である。

DateLastAccessed(最終アクセス日時)

これは、「ファイルの内容が読み取られた、あるいは属性が参照された瞬間」を指す。
ここが初心者の陥る最大の罠だ。

「ファイルを開いて中身を見た」ときだけではなく、以下のケースでも更新される可能性がある。

  • アンチウイルスソフトによるスキャン
  • Windows Searchインデックス作成サービスによる巡回
  • バックアップソフトによる読み取り

つまり、「人間がそのファイルを利用したかどうか」は、`DateLastAccessed` だけでは担保できないのだ。

2. 設計思想:どのプロパティを「真実」とするか

実務における設計指針を明確に定義しておく。

ケースA:監査ログ・履歴管理

採用すべき指標:`DateLastModified`
「いつ、誰が、どのデータを更新したか」を記録する場合、アクセス日時はノイズでしかない。インデックス作成サービスがファイルを触っただけで「アクセスがあった」と記録されては、監査の意味をなさない。

ケースB:不要ファイルの自動削除(クリーンアップ)

採用すべき指標:`DateLastModified` + 余裕を持たせた判定
「一定期間使われていないファイルを消す」という要件に対し、安易に `DateLastAccessed` を使うのは危険だ。上述の通り、システムプロセスによる「誤検知」が頻発するからだ。

もし「本当に誰も見ていないファイル」を特定したいのであれば、`DateLastAccessed` を利用するにしても、「システムによるスキャンが頻繁に行われる環境では、アクセス日時の判定は行わない」という判断を下すのが、アーキテクトとしての正しい設計である。

3. プロダクション・コード:堅牢なファイル判定エンジン

では、実際に現場で使えるコードを示そう。単なる比較ではなく、エラーハンドリングと、オブジェクトのライフサイクルを考慮した、保守性の高い実装だ。

以下のスクリプトは、指定したフォルダ内のファイルを走査し、「更新日時」に基づいて「更新が必要なファイル」と「古いファイル」を分類する。

'**
' Script Name: FileTimestampAnalyzer.vbs
' Description: FSOを用いた堅牢なファイル日時判定スクリプト
' Author: Chief Architect
'**
Option Explicit

' 定数の定義(マジックナンバーを排除し、保守性を高める)
Const DAYS_THRESHOLD = 30 ' 30日以上更新がないものを「古い」と判定

Dim fso, targetFolder, file
Dim targetPath

' 実行対象のパス(実際の実務では引数や設定ファイルから取得すべき)
targetPath = "C:\Your\Target\Folder" 

Set fso = CreateObject("Scripting.FileSystemObject")

' メインロジックの呼び出し
ExecuteFileAnalysis targetPath

' --- 関数定義 ---

Sub ExecuteFileAnalysis(path)
    On Error Resume Next ' エラーハンドリングの開始
    
    ' 1. ディレクトリの存在確認
    If Not fso.FolderExists(path) Then
        WScript.Echo "Error: 指定されたパスが存在しません: " & path
        Exit Sub
    End If

    Dim targetFolder
    Set targetFolder = fso.GetFolder(path)

    WScript.Echo "--- 分析開始: " & targetFolder.Path & " ---"
    WScript.Echo "判定基準: 更新日時が " & DAYS_THRESHOLD & " 日以上経過しているか"
    WScript.Echo "--------------------------------------------------"

    ' 2. ファイルのループ処理
    For Each file In targetFolder.Files
        ' ファイルへのアクセスエラー(使用中のファイル等)を考慮
        If Err.Number <> 0 Then
            WScript.Echo "[SKIP] アクセス失敗: " & file.Name & " (Error: " & Err.Description & ")"
            Err.Clear
        Else
            AnalyzeFile file
        End If
    Next

    WScript.Echo "--------------------------------------------------"
    WScript.Echo "分析完了。"
    
    ' オブジェクトの解放
    Set targetFolder = Nothing
    On Error GoTo 0
End Sub

Sub AnalyzeFile(fileObj)
    ' プロパティの取得
    Dim lastModified, lastAccessed, diffDays
    lastModified = fileObj.DateLastModified
    lastAccessed = fileObj.DateLastAccessed
    
    ' 差分計算(DateDiff関数を使用)
    ' "d" は日単位の差分
    diffDays = DateDiff("d", lastModified, Now())

    ' 判定ロジック
    ' ここでは「業務上の重要度」に基づき、DateLastModifiedを主軸に据える
    If diffDays >= DAYS_THRESHOLD Then
        WScript.Echo "[OLD] " & fileObj.Name & _
                     " | 更新: " & lastModified & _
                     " | (経過: " & diffDays & "日)"
    Else
        WScript.Echo "[OK ] " & fileObj.Name & _
                     " | 更新: " & lastModified & _
                     " | (アクセス: " & lastAccessed & ")"
    End If
End Sub

' オブジェクトのクリーンアップ
Set fso = Nothing

このコードの設計ポイント:

1. Error Handling (`On Error Resume Next`):
ファイル操作において、ファイルが他のプロセスによってロックされているケースは日常茶飯事だ。エラーを無視して止まるのではなく、エラーを検知して「スキップ」し、処理を継続させるのが業務ツールの鉄則である。
2. Separation of Concerns (関心の分離):
`ExecuteFileAnalysis`(走査)と `AnalyzeFile`(個別判定)を分けることで、判定ロジックの変更(例:更新日時ではなくファイルサイズも見るなど)に強い構造にしている。
3. Avoid Magic Numbers:
`30` という数値を直接ロジック内に書かず、定数 `DAYS_THRESHOLD` として定義している。これにより、将来の仕様変更時に修正箇所が一点で済む。
4. Resource Management:
スクリプトの終端で `Set fso = Nothing` を行い、オブジェクトのライフサイクルを明示的に管理している。大規模なループを回す際、メモリリークを防ぐための基本動作だ。

結論

`DateLastAccessed` は、OSという巨大な機構が管理する「目安」に過ぎない。
業務自動化エンジニアが信頼すべきは、常に `DateLastModified` である。

「なぜこのファイルは、触っていないはずなのにアクセス日時が変わっているのか?」
この問いに答えられるようになれば、君の書くスクリプトは、単なる「動くコード」から、「信頼に値するシステム」へと昇華するだろう。

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