【テクニカル・上級編】【実務中級者向け】FSO(FileSystemObject)連携:図面を開く前にファイルの更新日時とサイズをチェックする – AutoCAD VBA解析バイブル

スポンサーリンク

AutoCAD VBAを掌握する極限の知見:FSO連携によるDWG事前妥当性検証のアーキテクチャ

AutoCAD VBAによる図面バッチ処理において、最も避けるべき致命傷は何か。それは、「中身を確認する目的だけで、無駄に重いDWGファイルをメモリ上にロードしてしまうこと」である。

`Documents.Open`メソッドを安易にループさせ、ファイルを開いてからバージョンや最終更新日、サイズを確認する設計は、大規模な図面管理システムにおいては「罪」に等しい。AutoCADのCOMオブジェクトの初期化コストと、巨大なDWGパーシングのオーバーヘッドは、VBAランタイムの寿命を確実に縮める。

今回は、AutoCAD APIの死角を補い、ファイルシステム層で圧倒的な事前フィルタリングを実現する FileSystemObject(FSO) との連携、および実務で即座に使える堅牢な検証ロジックの全貌を解説する。

—

1. なぜAutoCAD API単体では不十分なのか

AutoCADの`Document`オブジェクトや`Database`オブジェクトは、図面が開かれた後でなければそのメタデータ(バージョン情報など)を完全に露出しない。

「特定のフォルダ内にある、昨日以降に更新された特定のフォーマットの図面だけを一括処理したい」という要件に対し、すべてのファイルを`Documents.Open`で開いて閉じるアプローチを取った場合:

  • メモリリークの温床: AutoCADのCOMインターフェースは解放タイミングがシビアであり、数千ファイルの処理で確実にメモリが枯渇する。
  • 排他制御の衝突: 他のユーザーがネットワーク上で開いている(`.LCK`ファイルが存在する等)ファイルを無理に開こうとして、VBAの実行時エラーでスクリプトがクラッシュする。
  • パフォーマンスの絶望的な低下: 不要な図面の読み込みにCPUとI/Oの大半が奪われる。

ここで登場するのが、Windows OSのファイルシステムへダイレクトにアクセスする `Scripting.FileSystemObject` である。

—

2. FSOを用いたメタデータ・プリチェックの極意

FSOを使用することで、CADエンジンを起動する前に、ファイルの物理的状態(タイムスタンプ、サイズ、属性、存在有無)をミリ秒単位で取得できる。

さらに、レガシーなDWGファイルのヘッダーバイナリを先頭数バイトだけ読み取る手法を組み合わせれば、「ファイルを開く前にAutoCADのバージョン(AC1015, AC1018, AC1021, AC1032など)を特定する」という高度な事前フィルタリングさえ可能になる。

実務レベル・堅牢性重視のFSO事前検証モジュール

以下に、実務の現場で即座に組み込めるプロダクション品質のコードを提示する。オブジェクトのライフサイクル管理、エラーハンドリング、そしてメモリの明示的解放を徹底した実装だ。

Option Explicit

‘ ==============================================================================
‘ モジュール名: modFSOPreCheck
‘ 概要: FSOを活用したDWGファイルの事前妥当性検証およびバージョン判定
‘ =================5=============================================================

Public Sub ExecuteDWGPreCheckPipeline()
Dim targetFolderPath As String
targetFolderPath = “C:\DWG_WorkSpace\TargetDrawers” ‘ 監視対象パス

Dim fso As Object
Dim targetFolder As Object
Dim fileItem As Object

‘ FSOのインスタンス生成(早期バインディング推奨だが環境依存を考慮しCreateObject)
Set fso = CreateObject(“Scripting.FileSystemObject”)

If Not fso.FolderExists(targetFolderPath) Then
MsgBox “指定されたディレクトリが存在しません: ” & targetFolderPath, vbCritical
Exit Sub
End If

Set targetFolder = fso.GetFolder(targetFolderPath)

‘ ログ出力または処理リストの初期化
Debug.Print “=== DWG Pre-Check Pipeline Started ===”

On Error GoTo ErrorHandler

For Each fileItem In targetFolder.Files
‘ 1. 拡張子のフィルタリング (.dwg のみ対象)
If LCase(fso.GetExtensionName(fileItem.Name)) = “dwg” Then

‘ 2. FSOによる物理特性チェック
Call AnalyzeFileProperties(fileItem)

End If
Next fileItem

CleanUp:
‘ オブジェクトの明示的解放(メモリ最適化の極意)
Set fileItem = Nothing
Set targetFolder = Nothing
Set fso = Nothing
Debug.Print “=== DWG Pre-Check Pipeline Finished ===”
Exit Sub

ErrorHandler:
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical
Resume CleanUp
End Sub

Private Sub AnalyzeFileProperties(ByRef fileItem As Object)
Dim fsoDateLastModified As Date
Dim fileSizeByte As Currency
Dim dwgVersion As String

‘ — A. FSOプロパティの取得 —
fsoDateLastModified = fileItem.DateLastModified
fileSizeByte = fileItem.Size

‘ — B. 業務ロジックに基づくフィルタリング条件の例 —
‘ 例: 「過去24時間以内に更新され、かつサイズが0バイトではない(破損していない)」
If fsoDateLastModified >= (Now – 1) And fileSizeByte > 0 Then

‘ — C. バイナリレベルでのDWGバージョン判定(高度な拡張) —
dwgVersion = GetDWGVersionFromBinary(fileItem.Path)

Debug.Print “【処理対象候補】” & _
vbCrLf & ” ファイル名: ” & fileItem.Name & _
vbCrLf & ” 更新日時: ” & fsoDateLastModified & _
vbCrLf & ” サイズ: ” & Format(fileSizeByte, “#,

0″) & ” Bytes” & _

vbCrLf & ” 推定バージョン: ” & dwgVersion

‘ ここで初めて AutoCAD の Documents.Open を呼び出す判断を下す
‘ Call OpenDrawingSafely(fileItem.Path)

Else
Debug.Print “【スキップ】 ” & fileItem.Name & ” (条件不一致または古いファイル)”
End If
End Sub

Private Function GetDWGVersionFromBinary(ByVal filePath As String) As String
‘ DWGファイルの先頭6バイト(Sentinel)からバージョンを特定する
‘ 例: AC1015 = AutoCAD 2000, AC1018 = AutoCAD 2004, AC1032 = AutoCAD 2018-2024
Dim fileNum As Integer
fileNum = FreeFile

Dim headerBytes(0 to 5) As Byte
Dim versionStr As String
versionStr = “Unknown”

On Error GoTo BinaryReadError

Open filePath For Binary Access Read Lock Read Write As #fileNum
Get #fileNum, 1, headerBytes
Close #fileNum

‘ バイト配列を文字列に変換
Dim i As Integer
For i = 0 To 5
versionStr = versionStr & Chr(headerBytes(i))
Next i

‘ プレフィックスの抽出 (AC10xxの部分)
If InStr(versionStr, “AC10”) > 0 Then
GetDWGVersionFromBinary = Mid(versionStr, InStr(versionStr, “AC10”), 6)
Else
GetDWGVersionFromBinary = “Unsupported/Corrupted”
End If
Exit Function

BinaryReadError:
Close #fileNum
GetDWGVersionFromBinary = “Read Error”
End Function

—

3. チーフアーキテクトが説く「メモリ最適化とリソース管理」の鉄則

上記のコードにおいて、なぜこれほどまでにオブジェクトの解放やエラーハンドリングに気を配っているのか。VBAランタイムとAutoCADのCOMプロセスが混在する環境では、以下の原則がシステム全体の安定性を左右する。

1. `Set obj = Nothing` の徹底とスコープの局所化

VBAのガベージコレクションは参照カウント方式をとっている。`For Each` ループ内でCOMオブジェクトやFSOオブジェクトを生成・破棄する際、参照が残ったままだとヒープ領域を圧迫し、大規模図面の処理中に「メモリ不足 (Out of memory)」エラーを引き起こす。変数のスコープは可能な限り狭くし、処理が終わった瞬間に `Nothing` を代入して参照を断ち切るべきだ。

2. ネットワークドライブ(UNCパス)におけるFSOの挙動

社内サーバーやNAS上のDWG群を対象とする場合、FSOの `DateLastModified` や `Size` の取得はネットワークI/Oを発生させる。
もし数万ファイル規模のディレクトリをスキャンする場合、無駄なプロパティアクセスはスクリプトを著しく重くする。そのため、本稿で示したように「更新日時」や「ファイルサイズ」による一次フィルターをかけ、通過したものだけに対して詳細なバイナリ解析やCADオープンを行うパイプライン構造が絶対的な正解となる。

3. ファイルロックの安全なハンドリング

他のユーザーがAutoCADで編集中、あるいはバックアップ処理が走っている最中のDWGファイルにアクセスすると、VBAは容赦なく実行時エラー(権限エラーなど)を吐く。
FSOだけでは「排他ロックされているか」の正確な判定が難しいため、上記コードのバイナリ読み込み部分のように、`Open … For Binary Access Read Lock Read Write` を用いて、OSレベルで安全に読み込み権限が確保できるか確認する防衛的プログラミングが不可欠である。

—

4. 結びにかえて

真にスケーラブルなAutoCAD自動化アーキテクチャとは、「AutoCADに頼らない処理は、AutoCADの外で完結させる」という冷徹なまでの効率化の追求によって成り立つ。

FSOを活用したファイルシステムの事前検証は、単なる「便利機能」ではない。それは、レガシーなCAD環境を安定稼働させ、夜間バッチや自動化パイプラインを絶対に止äusさないための、シニアエンジニア必携の防衛網なのである。無駄なオーバーヘッドを削ぎ落とし、真に価値のある図面データ処理にのみリソースを集中させよ。

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