もう解凍はいらない:VBAでZIPのファイル一覧を取得する
ZIPファイルの中身だけを確認したい場面は多くあります。例えば、添付ファイルの受け取り後に、不要な解凍を避けて中身をチェックしたい、特定の拡張子だけを抽出したい、複数のZIPから一括で一覧を作りたい、などです。本記事では、Excelを想定したVBAだけでZIPのファイル一覧を取得する方法を中心に、代替手段との比較、準備手順、実装関数、使い方、エラー対処までをまとめます。
前提環境は、WindowsとExcel(デスクトップ版)です。企業ネットワークやセキュリティ設定により、一部の操作が制限されることがあります。ここで紹介する内容は一般的な情報であり、個別環境への適合や動作保証は行いません。社内ポリシーやセキュリティ規程に従ってご利用ください。
ZIP一覧化は無料の機能だけで可能?
VBAとWindowsに標準で含まれる機能(Shell.Applicationや“ZIPフォルダ”機能)で、追加の有料ツールなしに一覧化は可能です。外部ツール連携を使う場合も、無料の選択肢(PowerShellや7-Zipなど)があります。導入や権限の要否は環境により異なるため、テスト用のフォルダで動作確認するのが安全です。
ZIPの中身を確認する3つの方法
まずは標準のShell.Applicationでニーズを満たせるかを確認するのが近道です。管理ポリシーが厳しい環境では外部ツールの導入が難しいため、VBAのみの方法が初手として扱いやすくなります。一方で、巨大なZIPや大量処理では、PowerShellや7-Zipを併用すると速度や詳細情報の面で有利なことがあります。
ZIPの中身を一覧化する方法は大きく3つに分けられます。ここでは、考え方と向き不向きを把握しやすいように整理します。
- VBAからShell.Applicationを使う方法(解凍不要・標準機能)
- Windowsの“ZIPフォルダ”を前提に、VBAで列挙する方法(1の実体に近い)
- 外部コマンド(PowerShellや7-Zipなど)をVBAから呼び出す方法
それぞれの特徴
| 方法 | 追加インストール | 権限の影響 | サブフォルダの列挙 | 速度/安定性 | 向いている用途 |
|---|---|---|---|---|---|
| Shell.Application(VBAのみ) | 不要 | 一般ユーザーで可のことが多い | 可能(再帰で対応) | 中程度 | Excelからの軽量な一覧化 |
| ZIPフォルダ前提(同上) | 不要 | 同上 | 可能 | 中程度 | エクスプローラー相当の列挙 |
| PowerShell呼び出し | 不要(標準搭載) | 実行ポリシーで制限される場合あり | 可能 | 中〜速 | 追加情報取得やスクリプト連携 |
| 7-Zipコマンド | 必要(無償) | インストール権限が必要 | 可能 | 速いことが多い | 大量ZIPの高速処理やCI連携 |
解凍せずに安全に中身だけ見るコツは?
- 信頼できる保存先(検証用フォルダ)でテストする。
- 読み取り専用の操作にとどめる(展開・上書きは行わない)。
- パス長や日本語を含むパスを想定して、テストケースを複数用意する。
- ネットワークドライブ上のZIPは一度ローカルにコピーしてから確認すると安定することがある。
事前準備:参照設定
この記事のサンプルは、基本的に参照設定なし(遅延バインディング)で動きます。これにより、特定の参照設定に依存せずに実行できる可能性が高まります。必要に応じて次の項目を検討してください。
- 参照設定なし(推奨):CreateObject(“Shell.Application”)を生成します。
- 任意の参照:Microsoft Scripting Runtime(DictionaryやFileSystemObjectを使う場合)。
- マクロ実行ポリシー:信頼されている場所のブックや、署名付きマクロなど、社内規程に沿った設定が必要な場合があります。
また、共有フォルダやネットワークドライブを扱う場合は、パスの表記(UNCパスやドライブ割り当て)に注意してください。アクセス権限により、ZIPの読み取り自体が拒否されることもあります。
参照設定なし(遅延バインディング)でも動く?
動きます。Shell.ApplicationやコレクションはAs Objectで扱い、早期バインディング特有の定数や型を使わないようにすれば、参照設定なしで実行できます。型の恩恵(補完や定数)は少なくなりますが、配布性は高くなります。
ZIP内の全てのファイルパスを取得する関数(GetZipFileList)
ここでは、ZIPの中にある全ファイル(サブフォルダ内も含む)のパスを、解凍せずに取得する関数を示します。返り値は文字列の一次元配列です。フォルダ自体(ディレクトリ)を除外し、ファイルのみを収集します。
ソースコード
Option Explicit
‘ ZIP内のファイルの仮想パスを配列で返す
‘ 例: “docs/report.txt” のような相対パスを返します
Public Function GetZipFileList(ByVal zipPath As String) As Variant
Dim sh As Object ‘ Shell.Application
Dim zipNS As Object ‘ Folder (Shell NameSpace)
Dim results As Object ‘ Collection
Dim arr() As String
On Error GoTo ExitWithError
If Len(Dir$(zipPath, vbNormal)) = 0 Then
Err.Raise vbObjectError + 100, , “ZIPファイルが見つかりません: ” & zipPath
End If
Set sh = CreateObject(“Shell.Application”)
Set zipNS = sh.NameSpace(zipPath)
If zipNS Is Nothing Then
Err.Raise vbObjectError + 101, , “ZIPを開けませんでした(関連付け/ポリシーを確認): ” & zipPath
End If
Set results = CreateObject(“System.Collections.ArrayList”)
‘ 再帰的に列挙
Call RecurseZipFolder(zipNS, “”, results)
If results.Count = 0 Then
GetZipFileList = VBA.Array() ‘ 空配列
Exit Function
End If
ReDim arr(0 To results.Count – 1)
Dim i As Long
For i = 0 To results.Count – 1
arr(i) = CStr(results.Item(i))
Next
GetZipFileList = arr
Exit Function
ExitWithError:
GetZipFileList = VBA.Array()
End Function
‘ 再帰列挙のヘルパー
Private Sub RecurseZipFolder(ByVal folderObj As Object, ByVal basePath As String, ByVal results As Object)
Dim it As Object
For Each it In folderObj.Items
If CBool(it.IsFolder) Then
‘ サブフォルダの中身を再帰列挙
On Error Resume Next
Dim subF As Object
Set subF = it.GetFolder
On Error GoTo 0
If Not subF Is Nothing Then
Call RecurseZipFolder(subF, CombinePath(basePath, CStr(it.Name)), results)
End If
Else
results.Add CombinePath(basePath, CStr(it.Name))
End If
Next
End Sub
‘ パス結合(ZIP内の仮想パスを”/”で統一)
Private Function CombinePath(ByVal basePath As String, ByVal nameOnly As String) As String
If Len(basePath) = 0 Then
CombinePath = nameOnly
Else
CombinePath = basePath & “/” & nameOnly
End If
End Function
使いどころと制限
- ZIP内のフォルダ階層を維持した一覧が得られます。
- 取得対象はファイルのみ(ディレクトリは含めません)。
- 一部の特殊なZIP(非常に深い階層や巨大ファイルを多く含むもの)では、列挙に時間がかかることがあります。
- ネットワーク越しのZIPでは、タイムアウトや応答遅延が発生することがあります。
コードの解説
- Shell.ApplicationとNameSpace: ZIPはエクスプローラー経由で“仮想フォルダ”として扱えます。NameSpace(zipPath)で中身にアクセスできます。
- 再帰列挙: IsFolderで分岐し、フォルダならGetFolderで内部を取得、ファイルなら結果に追加します。
- 仮想パスの表現: CombinePathで、ZIP内のパスを「/」で結合し、表示やフィルタに使いやすくしています。
- エラー処理: NameSpaceがNothingになる場合があるため、早めに中断して空配列を返します。
フォルダ階層や巨大ZIPでも使える?
基本的に再帰で対応します。ただし、非常に大きなZIPでは処理時間が伸び、メモリ消費も増えます。必要に応じて、件数制限や拡張子フィルタを加えることで負荷を抑えられます。
使用例
次の例は、GetZipFileListの結果をシートに書き出す最小構成です。列AにZIP内パス、Bに拡張子、Cに最終更新日時(不明時は空)を出力します。
Public Sub ExportZipListToSheet()
Dim zipPath As String
zipPath = Application.GetOpenFilename(“ZIPファイル (*.zip),*.zip”)
If VarType(zipPath) = vbBoolean Then Exit Sub ‘ キャンセル
Dim arr As Variant
arr = GetZipFileList(zipPath)
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets.Add
ws.Name = “ZipList”
ws.Range(“A1”).Value = “PathInZip”
ws.Range(“B1”).Value = “Ext”
ws.Range(“C1”).Value = “Modified”
If IsEmpty(arr) Then Exit Sub
Dim i As Long
For i = LBound(arr) To UBound(arr)
Dim p As String: p = CStr(arr(i))
ws.Cells(i + 2, 1).Value = p
ws.Cells(i + 2, 2).Value = Mid$(p, InStrRev(p, “.”) + 1)
Next
‘ 参考: 更新日時などのメタ情報が必要な場合は、ShellのGetDetailsOfで列挙する方法もあります
‘ ここでは一覧に特化し、速度優先でパスのみを出力しています
ws.Columns.AutoFit
End Sub
一覧を表形式で出すベストプラクティスは?
- 列は、パス、拡張子、サイズ、更新日時など固定で用意すると後処理が楽になります。
- 1ZIP=1シート、またはZIP名をキーに同一シートへ追記する方式のどちらかに統一します。
- 検索やピボットを想定し、ヘッダー名は英数字で揃えると関数から参照しやすくなります。
よくあるエラーと対処法
実装時に遭遇しやすい問題を、原因と対処の観点でまとめます。環境依存の要素があるため、本番ファイルではなく検証用のコピーで試すのが安全です。
エラー1:「ZipFile型が見つかりません」
VBA標準にZipFileという型はありません。外部ライブラリを想定したサンプルを流用したときに出やすいエラーです。この記事のコードは遅延バインディングを用い、型名に依存していません。As Objectで宣言し、CreateObjectで生成する方式に変更してください。
エラー2:日本語ファイル名が文字化け
Shell.Application経由では、一般的な日本語ファイル名はそのまま取得できます。もし文字化けが起きる場合は、
- 文字コード変換を行う外部処理と混在していないか
- 出力先のCSVで文字コードをUTF-8にしていないか(Excel版によっては再現)
- デバッグプリント時にフォント依存の表示乱れがないか
などを確認してください。シート出力時は標準の文字列型を使えば多くのケースで問題なく表示できます。
エラー3:「パスが見つかりません」
指定したzipPathが間違っている、またはアクセス権限がないと発生します。OpenFileDialogで選択したパスをそのまま使うか、Dir関数で存在確認を行い、ネットワークパスの場合は一度ローカルにコピーしてから試してください。ZIPが別プロセスでロックされている場合も失敗します。
エラー4:空の配列が返される
ZIPは開けたが、列挙対象が見つからない場合に発生します。フォルダしか含まれていないZIP、もしくはフィルタ条件で除外された可能性があります。テストとして拡張子を限定せずに実行し、ZIPの中身がファイルを含んでいるかを確認してください。
社内PCで動かないとき最初に見る場所は?
- マクロ実行が許可されているか(信頼済みの場所や署名付きブック)
- ZIPのある場所への読み取り権限があるか
- 実行ユーザーのポリシーでShellの利用が制限されていないか
- ネットワーク経由の場合はローカルコピーで再現するか