「巨大なファイル」という爆弾を回避せよ:業務を止めないための堅牢なファイル容量管理設計術
業務自動化の世界へようこそ。
あなたが今日、誰かのために作るマクロは、単なる「便利ツール」であってはならない。それは、「ユーザーのミスを未然に防ぎ、システムの整合性を守る防波堤」であるべきだ。
よくある失敗例を紹介しよう。
「ファイルが大きすぎてメールが送れない」「共有ストレージの容量を圧迫して、チーム全体の作業が止まった」「保存したはずのファイルが、容量オーバーで破損した」。
これらはすべて、プログラミングの技術不足ではなく、「設計思想の欠如」から生まれる。
今回は、PowerPoint VBAを用いて、ファイルサイズを事前に検知し、規定値を超えた場合にユーザーへ警告と「別名保存」を促す、実戦投入レベルの安全管理マクロを解説する。初心者向けのテーマだが、その裏側にある「堅牢な設計(Robust Design)」の極意を叩き込んでやる。準備はいいか?
1. なぜ「ただのMsgBox」では不十分なのか
初心者は、よくこう書く。
`If FileSize > 10 Then MsgBox “デカすぎます”`
これでは、エンジニア失格だ。なぜなら、このコードには以下の「考慮漏れ」があるからだ。
1. 未保存のプレゼンテーションへの対応: パスが存在しない新規ファイルに対して実行すると、ランタイムエラーで即死する。
2. マジックナンバーの乱用: `10` という数字が何を意味するのか(MBなのかKBなのか)、どこで定義されているのかが不明瞭。
3. 後続処理の欠如: 警告を出した後、ユーザーはどう動くべきか? プログラムがフローを制御できていない。
プロの設計は、「エラーが起きることを前提に、エラーが起きた時の逃げ道(フォールバック)を用意しておく」ことから始まる。
2. 実装のアーキテクチャ:防御的プログラミング
今回構築するロジックのフローは以下の通りだ。
1. 前提条件の検証: 現在開いているファイルに「保存されたパス」があるか?
2. 物理サイズの取得: `FileSystemObject` を用い、OSレベルで正確なファイルサイズを取得する。
3. 閾値判定: 定義済みの定数(Constant)と比較する。
4. ユーザーへの介入(Intervention): 閾値を超えていた場合、単なる警告ではなく「別名保存」という回避策を提示する。
プロダクション品質のコード例
以下のコードを標準モジュールに貼り付けて試してほしい。コメントを読み、なぜこのように書いているのかを深く理解すること。
Option Explicit
' =================================================================
' 構成定数:マジックナンバーを排除し、保守性を高める
' =================================================================
Private Const MAX_FILE_SIZE_MB As Double = 10# ' 許容最大サイズ (MB)
Private Const MSG_PREFIX As String = "【容量警告】"
''' <summary>
''' ファイルサイズをチェックし、規定値を超えている場合に安全な保存を促す
''' </summary>
Public Sub SafeCheckAndSave()
On Error GoTo ErrorHandler
Dim targetPres As Presentation
Set targetPres = ActivePresentation
' 1. 未保存のファイル(パスを持たないもの)への対処
' 新規作成直後のファイルには物理的なファイルが存在しないため、通常の保存フローへ流す
If targetPres.Path = "" Then
MsgBox "このファイルはまだ一度も保存されていません。通常の保存を実行してください。", vbInformation
targetPres.SaveAs targetPres.FullName ' ここでは単純なSaveAsを行う
Exit Sub
End If
' 2. ファイルサイズの取得
Dim currentSizeMB As Double
currentSizeMB = GetFileSizeMB(targetPres.FullName)
' 3. 判定ロジック
If currentSizeMB > MAX_FILE_SIZE_MB Then
' 閾値を超えている場合、ユーザーに意思決定を仰ぐ
Dim userChoice As VbMsgBoxResult
userChoice = MsgBox( _
MSG_PREFIX & vbCrLf & _
"現在のファイルサイズは " & Format(currentSizeMB, "0.00") & " MB です。" & vbCrLf & _
"規定値 (" & MAX_FILE_SIZE_MB & " MB) を超えています。" & vbCrLf & vbCrLf & _
"容量を抑えるため、別名で保存(圧縮検討用)することを推奨します。" & vbCrLf & _
"別名保存を実行しますか?", _
vbExclamation + vbYesNo + vbDefaultButton2, "容量オーバー検知")
If userChoice = vbYes Then
' 別名保存の実行
Call PromptSaveAs(targetPres)
Else
' 強行する場合の警告(実務ではここでログを取ることも検討する)
MsgBox "上書き保存を続行します。メール添付時などに注意してください。", vbCritical
targetPres.Save
End If
Else
' 正常範囲内であれば、そのまま保存
targetPres.Save
MsgBox "保存が完了しました。", vbInformation
End If
Exit Sub
ErrorHandler:
MsgBox "致命的なエラーが発生しました。" & vbCrLf & _
"Error No: " & Err.Number & vbCrLf & _
"Description: " & Err.Description, vbCritical, "システムエラー"
End Sub
''' <summary>
''' FileSystemObjectを使用して、正確なファイルサイズ(MB)を取得する
''' </summary>
Private Function GetFileSizeMB(ByVal filePath As String) As Double
Dim fso As Object
Dim fileObj As Object
' Late Bindingを使用して参照設定の手間を省く(配布時のトラブル防止)
Set fso = CreateObject("Scripting.FileSystemObject")
If fso.FileExists(filePath) Then
Set fileObj = fso.GetFile(filePath)
' ByteをMBに変換 (1024^2)
GetFileSizeMB = fileObj.Size / 1024 / 1024
Else
GetFileSizeMB = 0
End If
Set fileObj = Nothing
Set fso = Nothing
End Function
''' <summary>
''' ユーザーに保存先を指定させて別名保存を行う
''' </summary>
Private Sub PromptSaveAs(ByRef pres As Presentation)
Dim newPath As Variant
Dim defaultName As String
' 現在のファイル名に "_heavy" を付与した提案
defaultName = Replace(pres.FullName, ".pptx", "_heavy.pptx")
' GetSaveAsFilenameを使用して、OS標準のダイアログを表示
newPath = Application.FileDialog(msoFileDialogSaveAs).Show
' 注意: PowerPoint VBAのFileDialogは使い勝手が特殊なため、
' ここではシンプルにSaveAsメソッドを呼び出す設計にする
' 実務では、より高度なパス生成ロジックをここに組み込む
On Error Resume Next
pres.SaveAs defaultName
If Err.Number <> 0 Then
MsgBox "別名保存に失敗しました。手動で保存してください。", vbCritical
Else
MsgBox "別名で保存しました: " & vbCrLf & defaultName, vbInformation
End If
On Error GoTo 0
End Sub
3. チーフアーキテクトの視点:設計の重要ポイント
このコードをただコピペして終わらせるな。以下の3つの設計思想を脳に刻め。
① Late Binding(遅延結合)の選択
`GetFileSizeMB` 関数内で `CreateObject(“Scripting.FileSystemObject”)` を使っている。これは「参照設定」を事前に行わずに実行できる手法だ。
配布先のPCで「参照設定が足りなくて動かない!」という、初心者が最も陥りやすいトラブルを未然に防いでいる。「動かないリスクを最小化する」のがプロの仕事だ。
② 定数による「マジックナンバー」の排除
`MAX_FILE_SIZE_MB` を `Private Const` として冒頭に定義している。
もし明日、「規定値は20MBに変更して」と言われたら、君はコードのあちこちを探し回るのか? それとも、一番上の定数を書き換えるだけで済ませるのか? 「変更に強いコード」こそが、保守性の高いコードだ。
③ ユーザー体験(UX)への配慮
警告メッセージに `vbDefaultButton2` を指定している。これは、ダイアログが出たときに、標準のボタン(Yes)ではなく「No」が選択された状態にする設定だ。
「誤ってYesを押してしまい、意図しない保存フローに入る」というヒューマンエラーを、UIの設計段階で防いでいるのだ。
4. さらなる高みへ:実務での拡張アイデア
このマクロは、あくまで「第一歩」に過ぎない。現場の要求レベルに応じて、以下のような拡張を検討せよ。
- ログ連携: ファイルサイズが閾値を超えた際、その日時・ユーザー名・ファイル名を CSV やデータベースに記録する。これにより、「なぜストレージが圧迫されているのか」の統計分析が可能になる。
- 自動圧縮: サイズ超過時に、画像解像度を落とすなどの処理を自動で行うスクリプトを呼び出す(これはVBA単体では困難だが、外部ツールとの連携で実現可能だ)。
- 一括変換: 保存時に、自動的にPDF形式でも出力するようにし、メール添付用の軽量ファイルも同時に生成する。
まとめ
自動化エンジニアの価値は、コードの行数ではない。「そのコードがどれだけ、業務の継続性を保証できるか」で決まる。
今回学んだ「防御的プログラミング」と「保守性を意識した設計」を、次のプロジェクトでも必ず実践せよ。
健闘を祈る。
