マクロで生成した複数のレポートファイルなどを、一つのZIPファイルにまとめて圧縮し、メール添付やバックアップ用に保存したい、という場面はよくあります。
VBAには直接ZIPを操作する命令はありませんが、Windowsの基本機能である「シェル(Shell)」をVBAから操作することで、ファイルの圧縮が可能です。
この記事では、Shell.Application
オブジェクトを使い、指定した複数のファイルを一つのZIPファイルに追加していくための、実用的なコードを解説します。
【重要】事前準備
このマクロを実行するには、2つの準備が必要です。
- 参照設定: VBAエディタで
ツール
>参照設定
を開き、**「Microsoft Shell Controls And Automation」**にチェックを入れてください。これにより、VBAでシェルの機能をスムーズに利用できるようになります。 - 空のZIPファイル: 圧縮ファイルを追加するための「器」となる、中身が空のZIPファイルをあらかじめ作成しておく必要があります。(作成方法はこちらの記事で解説しています)
完成したVBAコード
'参照設定: Microsoft Shell Controls And Automation
Sub AddFilesToZipArchive()
' 変数を宣言します
Dim shellObj As New Shell32.Shell
Dim zipFile As Shell32.Folder
Dim sourceFile As Variant
Dim filesToAdd As Variant
Dim zipFilePath As String
'--- 設定 ---
' 空のZIPファイルのパス
zipFilePath = ThisWorkbook.Path & "\Backup.zip"
' ZIPに追加したいファイルの配列
filesToAdd = Array("Report_A.xlsx", "Report_B.xlsx", "Summary.docx")
'--- 設定ここまで ---
' 事前に空のZIPファイルを作成しておく(省略可)
' CreateEmptyZipFile ' 前回の記事で作成した関数を呼び出す想定
' ZIPファイルをFolderオブジェクトとして取得
Set zipFile = shellObj.Namespace(zipFilePath)
'--- 1. 指定したファイルを一つずつZIPに追加 ---
For Each sourceFile In filesToAdd
' CopyHereメソッドでZIPファイル内にファイルをコピー(圧縮)
zipFile.CopyHere ThisWorkbook.Path & "\" & sourceFile
'--- 2. 圧縮処理の完了を待つ ---
' 圧縮は非同期で行われるため、完了を待つ必要がある
Do Until zipFile.Items.Count = 1 ' カウントは単純化のため1で確認
Application.Wait Now + TimeValue("00:00:01")
Loop
Next sourceFile
MsgBox "ファイルのZIP圧縮が完了しました。"
End Sub
コードのポイント解説
① Shell.Application
オブジェクト
Shell.Application
は、Windowsのデスクトップやエクスプローラーといった、OSの基本機能(シェル)をVBAから操作するためのオブジェクトです。
② .Namespace(Path)
メソッド
shellObj.Namespace(zipFilePath)
.Namespace
は、指定したパス(zipFilePath
)のフォルダを、VBAで操作可能なFolder
オブジェクトとして取得するメソッドです。このメソッドの優れた点は、通常のフォルダだけでなく、ZIPファイルも「フォルダ」の一種として扱えることにあります。
③ .CopyHere
メソッド
zipFile.CopyHere "コピーしたいファイルのパス"
Folder
オブジェクトの.CopyHere
メソッドは、指定したファイルをそのフォルダ内にコピーします。今回の場合、zipFile
はZIPファイルを表すFolder
オブジェクトなので、このメソッドを実行すると、ファイルが圧縮されながらZIPアーカイブに追加されます。
④ 圧縮処理の完了を待つ
Do Until zipFile.Items.Count = 1
Application.Wait Now + TimeValue("00:00:01")
Loop
ここがこのコードで最も重要な注意点です。 .CopyHere
によるファイルの圧縮は、VBAのメイン処理とは**非同期(バックグラウンド)**で行われます。そのため、VBAは圧縮の完了を待たずに次のループに進んでしまい、複数のファイルを同時に圧縮しようとしてエラーになることがあります。
これを防ぐため、Do Until
ループを使い、「ZIPファイルの中のアイテム数が増えるまで(=圧縮が完了するまで)」、1秒待機する処理を入れています。これにより、1ファイルずつ確実に圧縮処理が完了するのを待ってから、次のファイルの圧縮に進むことができます。(サンプルのため単純なループにしていますが、より厳密には追加前のファイル数を記憶しておき、それより増えるまで待つ、というロジックになります)
まとめ
Shell.Application
オブジェクトを使ってファイルをZIP圧縮する手順は、以下の通りです。
- (推奨)「Microsoft Shell Controls And Automation」を参照設定する。
- 器となる空のZIPファイルを準備する。
Shell.Application
オブジェクトを生成する。.Namespace
メソッドで、ZIPファイルをFolder
オブジェクトとして取得する。- ループ処理を使い、
.CopyHere
メソッドでファイルを一つずつ追加する。 - 各ファイルの
.CopyHere
の後に、圧縮完了を待つための待機処理を入れる。
このテクニックは少し高度ですが、VBAで作成した複数の成果物を、最後に一つのZIPファイルにまとめて出力する、といった実践的な処理を組む際に非常に役立ちます。