【Java】7-Zipを使用したパスワード付きZIPファイルの解凍サンプル

## はじめに
業務でパスワード付きZIPファイルを解凍する必要がありましたが、Javaの標準ライブラリにはその機能が備わっていません。そこで、今回は7-Zipという外部ライブラリを使用して解凍処理を実装しました。本記事ではその実装方法を紹介します。

## 7-Zipとは？
7-Zipは、オープンソースのフリーソフトウェアで、様々な圧縮・解凍形式に対応しているツールです。パスワード付きZIPファイルの解凍にも対応しています。


### 対応形式

**圧縮/解凍(展開)**： 7z, XZ, BZIP2, GZIP, TAR, ZIP, WIM

**解凍(展開)のみ**： APFS, AR, ARJ, CAB, CHM, CPIO, CramFS, DMG, EXT, FAT, GPT, HFS, IHEX, ISO, LZH, LZMA, MBR, MSI, NSIS, NTFS, QCOW2, RAR, RPM, SquashFS, UDF, UEFI, VDI, VHD, VHDX, VMDK, XAR and Z.

https://7-zip.opensource.jp/


## サンプルプログラム
このプログラムは、パスワード付きのZIPファイルを解凍し、その中からPDFファイルを抽出して同じ階層に配置する処理を行います。使用しているJavaのバージョンは**11.0.25**です。

### 前提
以下のようなファイル構成を想定しています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3516839/90df0fa0-a9f8-46fc-4b03-c3761feccfaa.png" width=50%>

具体的には、SevenZipライブラリを使用して、指定されたパスワードで保護された**sample.zip**を解凍し、その中から**test.pdf**を抽出して解凍先のディレクトリ（ZIPファイルと同じ階層）に保存します。

### 依存ライブラリの追加
7-ZipをJavaで使用するためには、**sevenzipjbinding**ライブラリをプロジェクトに追加する必要があります。
今回は以下の依存関係をpom.xmlに追加します。

```pom.xml
<dependency>
    <groupId>net.sf.sevenzipjbinding</groupId>
    <artifactId>sevenzipjbinding</artifactId>
    <version>16.02-2.01</version>
</dependency>
```
詳細は以下のサイトを確認してください。

https://mvnrepository.com/artifact/net.sf.sevenzipjbinding/sevenzipjbinding/16.02-2.01

### サンプルコード
```java
    public static void unzipWithPassword() {
        // 解凍用パスワード
        String zipPassword = "sample";
        // 解凍対象のzipファイル
        File zipFile = new File("/home/sample.zip");

        try {
            // SevenZipライブラリを初期化
            SevenZip.initSevenZipFromPlatformJAR();
            // zipFileをRandomAccessFileで読取り専用（"r"）で開く
            RandomAccessFile randomAccessFile = new RandomAccessFile(zipFile, "r");
            // RandomAccessFileをIInStream型に変換
            IInStream inStream = new RandomAccessFileInStream(randomAccessFile);
            // ZIP形式のアーカイブを開く
            IInArchive archive = SevenZip.openInArchive(ArchiveFormat.ZIP, inStream, zipPassword);
            // ISimpleInArchive(IInArchiveを簡略化したインターフェース)を取得
            ISimpleInArchive simpleInArchive = archive.getSimpleInterface();
            // アーカイブ内の最初のアイテム（インデックス0）を取得
            ISimpleInArchiveItem archiveFile = simpleInArchive.getArchiveItem(0);

            // アーカイブアイテムのファイル名（パスを含む）を取得
            String pdfFileName = archiveFile.getPath();
            // zipFileの親ディレクトリを取得
            File zipFileDir = zipFile.getParentFile();
            // 解凍先のファイルをzipFileと同じディレクトリに作成
            File extractedFile = new File(zipFileDir, pdfFileName);
            
            try {
                // extractedFileに書き込みを行うためのFileOutputStreamを作成
                FileOutputStream zipFileOutputStream = new FileOutputStream(extractedFile);
                // バイト配列にデータを書き込むためのByteArrayOutputStreamを作成
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                
                // 'extractSlow'メソッドを使用して、アーカイブファイルを解凍
                ExtractOperationResult result = archiveFile.extractSlow(data -> {
                    try {
                        // データをバイト配列に書き込む
                        byteArrayOutputStream.write(data);
                    } catch (IOException e) {
                        logger.error("Caught exception", e);
                    }
                    return data.length;
                }, zipPassword);

                // 解凍結果の確認
                if (result != ExtractOperationResult.OK) {
                    System.err.println("解凍失敗");
                } else {
                    // 解凍したデータをファイルに書き込み
                    zipFileOutputStream.write(byteArrayOutputStream.toByteArray());
                    System.out.println("解凍成功: " + extractedFile.getAbsolutePath());
                }
            } catch (IOException e) {
                logger.error("Caught exception", e);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (SevenZipNativeInitializationException | SevenZipException e) {
            logger.error("Caught 7-Zip exception", e);
        } 
    }
```



## さいごに
今回はJavaで7-Zipを使ってパスワード付き圧縮ファイルを解凍するサンプルプログラムを紹介しました。
少しでも参考になれば幸いです。