Zip4jを使ってパスワード付ZIPファイルを作成するサンプル

#概要

Zip4jを使ってパスワード付ZIPファイルを作成するサンプルです。

対象のファイルがディレクトリの場合、サブディレクトリも含めて全てのファイルを、階層構造を維持したまま圧縮します。

#試した環境
- jdk 1.8.0_20
- zip4j 1.3.2

#サンプルコード

##ZipFileを使う

```java

import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;

import java.io.IOException;

public class ZipUtil {

    private int compressionMethod = Zip4jConstants.COMP_DEFLATE;
    private int compressionLevel = Zip4jConstants.DEFLATE_LEVEL_NORMAL;
    private int encryptionMethod = Zip4jConstants.ENC_METHOD_STANDARD;
    private int aesKeyStrength = Zip4jConstants.AES_STRENGTH_256;

    public ZipUtil(){
    }

    public ZipUtil(int encryptionMethod, int aesKeyStrength) {
        this.encryptionMethod = encryptionMethod;
        this.aesKeyStrength = aesKeyStrength;
    }

    public void zip(String input, String output, String password)
            throws ZipException, IOException {
        zip(input, output, password, "");
    }

    public void zip(String input, String output, String password, String fileNameCharset)
        throws ZipException, IOException {

        ZipFile zipFile = new ZipFile(output);
        // If the fileNameCharset is empty then charset is detected automatically
        // Try with Cp850 and UTF8 or OS default
        if (!fileNameCharset.isEmpty()) {
            zipFile.setFileNameCharset(fileNameCharset);
        }

        ZipParameters parameters = new ZipParameters();
        parameters.setCompressionMethod(compressionMethod);
        parameters.setCompressionLevel(compressionLevel);
        parameters.setEncryptFiles(true);
        parameters.setEncryptionMethod(encryptionMethod);
        parameters.setAesKeyStrength(aesKeyStrength);
        parameters.setPassword(password);

        File inputFile = new File(input);
        if (inputFile.isDirectory()) {
           zipFile.createZipFileFromFolder(inputFile, parameters, false, 0);
        } else {
           zipFile.addFile(inputFile, parameters);
        }
    }

    public void unzip(String input, String output, String password) throws ZipException {
        ZipFile zipFile = new ZipFile(input);
        if (zipFile.isEncrypted()) {
            zipFile.setPassword(password);
        }
        zipFile.extractAll(output);
    }
}

```


##ZipOutputStreamを使う

```java
import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.io.ZipOutputStream;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;

import java.util.Arrays;
import java.util.LinkedList;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class ZipUtil {

    private int compressionMethod = Zip4jConstants.COMP_DEFLATE;
    private int compressionLevel = Zip4jConstants.DEFLATE_LEVEL_NORMAL;
    private int encryptionMethod = Zip4jConstants.ENC_METHOD_STANDARD;
    private int aesKeyStrength = Zip4jConstants.AES_STRENGTH_256;

    public ZipUtil() {
    }

    public ZipUtil(int encryptionMethod, int aesKeyStrength) {
        this.encryptionMethod = encryptionMethod;
        this.aesKeyStrength = aesKeyStrength;
    }

    public void zip(String input, String output, String password)
            throws ZipException, IOException, CloneNotSupportedException {
        zip(input, output, password, "");
    }

    public void zip(String input, String output, String password, String fileNameCharset)
            throws ZipException, IOException, CloneNotSupportedException {

        ZipModel zipModel = new ZipModel();
        // If the fileNameCharset is empty then charset is detected automatically
        // Try with Cp850 and UTF8 or OS default
        if (!fileNameCharset.isEmpty()) {
            zipModel.setFileNameCharset(fileNameCharset);
        }

        ZipParameters parameters = new ZipParameters();
        parameters.setCompressionMethod(compressionMethod);
        parameters.setCompressionLevel(compressionLevel);
        parameters.setEncryptFiles(true);
        parameters.setEncryptionMethod(encryptionMethod);
        parameters.setAesKeyStrength(aesKeyStrength);
        parameters.setPassword(password);
        parameters.setDefaultFolderPath(new File(input).getParent());

        try (
            ZipOutputStream outputStream = new ZipOutputStream(new FileOutputStream(new File(output)), zipModel)
        ){
            LinkedList<File> remained = new LinkedList();
            remained.add(new File(input));
            while (!remained.isEmpty()) {
                File file = remained.pollFirst();
                outputStream.putNextEntry(file, (ZipParameters)parameters.clone());
                if (file.isDirectory()) {
                    remained.addAll(0, Arrays.asList(file.listFiles()));
                } else {
                    try (
                        InputStream inputStream = new FileInputStream(file)
                    ){
                        byte[] readBuff = new byte[4096];
                        int readLen = -1;
                        while ((readLen = inputStream.read(readBuff)) != -1) {
                            outputStream.write(readBuff, 0, readLen);
                        }
                    }
                }
                outputStream.closeEntry();
            }
            outputStream.finish();
        }
    }

    public void unzip(String input, String output, String password) throws ZipException {
        ZipFile zipFile = new ZipFile(input);
        if (zipFile.isEncrypted()) {
            zipFile.setPassword(password);
        }
        zipFile.extractAll(output);
    }
}

```

#使用例

```java
// Standard Enc
new ZipUtil().zip("/Users/hoge/file", "/Users/hoge/file.zip", "password");

// AES
new ZipUtil(Zip4jConstants.ENC_METHOD_AES, Zip4jConstants.AES_STRENGTH_256).zip("/Users/hoge/file", "/Users/hoge/file.zip", "password");

// Windowsで作成したファイルを圧縮
new ZipUtil().zip("/Users/hoge/file", "/Users/hoge/file.zip", "password", "windows-31j");

// Unzip
new ZipUtil().unzip("/Users/hoge/file.zip", "/Users/hoge/file", "password");

```

#補足

##ファイル名の文字コードについて

ZipModel.fileNameCharsetを指定している場合、指定された文字コードでエンコードする。
指定していない場合、自動判定。CP850, UTF8でエンコード、デコードしてみて元の文字列と一致するか判定する。どちらもあてはまらなければOSのデフォルトを使う。

ソースはこの辺

- HeaderWriter.writeLocalFileHeader
- Zip4jUtil.detectCharset

#参考

http://www.lingala.net/zip4j/index.php