【入門編】【上級者】ネットワーク経由でのPDF一括エクスポート時、一時的な回線切断やパケットロス発生時にトランザクションを安全にロールバックし、不完全な成果物を自動削除するレジリエント制御マクロ – PowerPoint VBA解析バイブル

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

ネットワークの向こう側にある「不完全なファイル」を許さない。VBAで実装するレジリエント(回復力のある)な一括エクスポート術

こんにちは。今日もコードと向き合っているあなた、素晴らしいですね。

「マクロの記録」を使って、自動化の第一歩を踏み出した。それはエンジニアとして非常に正しいステップです。でも、あなたが現場で「実戦」に投入しようとしたとき、ある壁にぶつかるはずです。

それは、「プログラムは完璧なのに、ネットワークが原因で失敗する」という問題です。

例えば、VPN越しに共有サーバーへPDFを一括保存するマクロを書いたとしましょう。通信が不安定なとき、保存の途中で一瞬だけパケットが途切れることがあります。するとどうなるか? サーバーには、「中身が空っぽのPDF」や「開こうとするとエラーが出る破損したPDF」がポツンと残されてしまうのです。

これでは、自動化どころか、後で人間が「どれが正しいファイルか」を確認する手間が増えてしまいますよね。

今日は、そんな「現場の理不尽」を技術でねじ伏せる、トランザクション(一連の処理)の整合性を守るためのレジリエント(回復力のある)な制御手法を伝授します。ここをマスターすれば、あなたの作るツールは「動くだけのツール」から「プロが信頼するシステム」へと進化します。

1. なぜ「ただの保存」ではダメなのか?(概念の理解)

まず、私たちが戦っている相手を理解しましょう。

通常の「マクロの記録」で作ったコードは、以下のような考え方です。
1. ファイルを開く
2. PDFとして保存する
3. 次のファイルへ行く

これ、実は非常に危ういんです。「2」の途中で通信が切れた場合、プログラムは「エラー」として止まるか、あるいは「不完全なファイルを作ったまま、そのまま次の処理に進んでしまう」からです。

プロの設計では、これを「原子性(Atomicity)」という考え方で制御します。
「保存が完全に成功したか、さもなくば、最初から何もなかったことにする(ロールバック)」という考え方です。

今回実装する「レジリエント制御」のフロー図

[開始]
  │
  ├─ ファイルを一つ選択
  │    │
  │    ├─ [Try: 実行フェーズ]
  │    │    └─ PDFとしてエクスポートを試みる
  │    │
  │    └─ [Catch: エラー検知フェーズ]
  │         │
  │         ├─ もし通信エラー等が発生したら...
  │         │    └─ [Rollback: 回復フェーズ]
  │         │         └─ 中途半端に生成されたゴミファイルを即座に削除!
  │         │
  │         └─ 成功したら、次のファイルへ
  │
[完了]

2. 実践:レジリエントPDFエクスポート・マクロ

それでは、実際に使えるコードを見ていきましょう。
このコードでは、`FileSystemObject`(ファイル操作のプロ)と、VBAの強力なエラーハンドリング機能 `On Error GoTo` を組み合わせています。

Option Explicit

''' <summary>
''' ネットワーク越しでも安全にPDFを一括エクスポートする
''' </summary>
Sub ResilientBatchPDFExport()
    Dim fso As Object
    Set fso = CreateObject("Scripting.FileSystemObject")
    
    ' --- 設定エリア ---
    Dim sourceFolder As String: sourceFolder = "C:\Your\Source\Path\"  ' 元のPPTXがあるフォルダ
    Dim targetFolder As String: targetFolder = "\\NetworkServer\Shared\PDF_Export\" ' 保存先(ネットワーク)
    ' ------------------

    Dim pptFile As Object
    Dim pptApp As PowerPoint.Application
    Dim pres As PowerPoint.Presentation
    Dim targetPath As String
    Dim fileNameOnly As String
    
    Set pptApp = PowerPoint.Application
    
    ' フォルダ内のファイルを取得するループ(簡易版)
    ' 本来はDir関数などでループさせますが、ここでは概念を明確にするため構造を示します
    Dim targetFile As String
    targetFile = Dir(sourceFolder & "*.pptx")
    
    Do While targetFile <> ""
        ' ファイル名(拡張子なし)を取得
        fileNameOnly = CreateObject("Scripting.FileSystemObject").GetBaseName(targetFile)
        targetPath = targetFolder & fileNameOnly & ".pdf"
        
        Debug.Print "Processing: " & targetFile
        
        ' --- トランザクション制御の開始 ---
        On Error GoTo ErrorHandler ' エラーが起きたら ErrorHandler ラベルへジャンプ
        
        ' 1. プレゼンテーションを開く
        Set pres = pptApp.Presentations.Open(sourceFolder & targetFile, ReadOnly:=msoTrue, WithWindow:=msoFalse)
        
        ' 2. PDFとして保存を試みる
        ' ここでネットワークが切れると、エラーが発生する
        pres.ExportAsFixedFormat Path:=targetPath, _
                                 FixedFormatType:=ppFixedFormatTypePDF, _
                                 Intent:=ppFixedFormatIntentPrint
        
        ' 3. 成功したら、ファイルを閉じる
        pres.Close
        Set pres = Nothing
        
        Debug.Print "Successfully exported: " & targetPath
        
        ' エラーハンドリングをリセットして次のファイルへ
        On Error GoTo 0
        
NextFile:
        targetFile = Dir() ' 次のファイルへ
    Loop
    
    MsgBox "全工程が完了しました。", vbInformation
    Exit Sub

ErrorHandler:
    ' --- ロールバック(回復)フェーズ ---
    Debug.Print "Error detected on " & targetFile & ": " & Err.Description
    
    ' もしファイルが中途半端に作られていたら、削除してクリーンアップする
    If fso.FileExists(targetPath) Then
        On Error Resume Next ' 削除自体が失敗する場合(ファイルがロックされている等)に備える
        fso.DeleteFile targetPath, True
        On Error GoTo 0
        Debug.Print "Rollback: Incomplete file deleted -> " & targetPath
    End If
    
    ' 開いているプレゼンテーションがあれば閉じる
    If Not pres Is Nothing Then pres.Close
    
    ' 次のファイルへ進むためにリセット
    Resume NextFile

End Sub

3. プロの視点:コードの「急所」を解説

このコード、ただ動くだけではありません。以下の3つのポイントが「プロの仕事」です。

① `On Error GoTo ErrorHandler` による「脱出路」の確保

初心者のうちは、エラーが出ると「マクロが止まって、どこまで終わったか分からなくなる」ことに恐怖を感じます。
このコードでは、エラーが起きた瞬間に `ErrorHandler` へワープさせ、「失敗したファイルを消す」→「次に進む」という動きを自動化しています。これがレジリエンス(回復力)の正体です。

② `FileSystemObject` による確実なクリーンアップ

`Kill` ステートメントでもファイル削除はできますが、`FileSystemObject` を使うことで、ファイルが存在するかどうかのチェック(`FileExists`)や、読み取り専用属性を無視した削除がより堅牢に行えます。
「ゴミを残さない」という強い意志が、この一行に込められています。

③ `Resume NextFile` による継続性

ここが最も重要です。エラーが起きたからといって、全ての処理を中止するのはもったいないですよね。
`Resume NextFile` を使うことで、「失敗したファイルは掃除して、次のファイルから再開する」という、止まらないパイプラインを実現しています。

4. さらに上を目指すあなたへ:究極の回避策「Staging Pattern」

もし、あなたが「絶対に、1%の破損も許されない」という極限のミッションを任されたら、どうするか?

その答えは、「いきなりネットワークに書き込まない」です。

1. ローカル(自分のPC)のTempフォルダにPDFを作る。
2. 完成した(エラーなく書き込めた)PDFだけを、最後にネットワークへ移動(Move)させる。

ネットワークへの移動は「書き込み」に比べて一瞬で終わるため、通信トラブルに巻き込まれる確率を劇的に下げられます。これを「ステージング・パターン」と呼びます。

' イメージ図
' 1. SaveAs "C:\Temp\result.pdf" (ローカルで安全に)
' 2. If Success Then fso.MoveFile "C:\Temp\result.pdf", "\\Network\result.pdf"

まとめ:制御を掌握すれば、VBAは武器になる

マクロの記録から一歩踏み出し、今回のような「エラーが起きたらどうするか?」「不完全な状態をどう防ぐか?」を考えるようになると、あなたの書くコードの質は劇的に変わります。

  • エラーは「防ぐもの」ではなく、「起きた後の動きを設計するもの」
  • データの整合性を守ることは、ユーザーの信頼を守ること

この視点を持っていれば、あなたはもう「マクロ使い」ではなく、立派な「自動化エンジニア」です。

さあ、勇気を持って、もっと複雑な、もっと大きな課題に挑戦していきましょう。応援していますよ!

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