LoginSignup
4
5

More than 5 years have passed since last update.

JavaでWindows環境で文字化けしないZip圧縮を行う

Last updated at Posted at 2017-10-18

JavaでファイルのZip圧縮を行う場合に、圧縮対象のファイル名に日本語文字が使われていると
一部のWindows環境で解凍時に文字化けが発生していたので、その回避方法を整理しました。

そもそも

Mac/Linuxで圧縮したファイルをWindowsで開いたりすると同様の問題が発生するケースがあります。
具体的にはWindows7 or WindowsServer2008R2でパッチが当たっていない場合に発生します。1

頼むから各種のパッチを当てて最新を使ってくれという気持ちになりますが
環境によっては容易に更新が行えないようなケースもあるため、その場合はプログラム側で対応しましょう。

実装

引数で指定されたファイル(またはディレクトリ)をpacked.zipというZipファイルに圧縮するサンプルです。

Java7からはZipOutputStreamのコンストラクタにCharsetを渡せるため
Charset.forName("Shift-JIS")を渡せばWindows環境でも文字化けしないZipファイルを作ることができます。

似た問題を探すとorg.apache.tools.zipパッケージを入れる必要があるという記事がいくつか見つかりますが
Java7からは標準ライブラリのみで実現できます。

ZipFile.java
package com.uskey512;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class ZipFile implements AutoCloseable {

    private byte[] buffer;
    private List<File> targetFiles;
    private ZipOutputStream zipOutputStream;

    private static final int DEFAULT_BUFFER_SIZE = 1024;

    public ZipFile(String fileName, String path) throws IOException {
        this(fileName, path, Charset.defaultCharset(), DEFAULT_BUFFER_SIZE);
    }

    public ZipFile(String fileName, String path, int bufferSize) throws IOException {
        this(fileName, path, Charset.defaultCharset(), bufferSize);
    }

    public ZipFile(String fileName, String path, Charset charset) throws IOException {
        this(fileName, path, charset, DEFAULT_BUFFER_SIZE);
    }

    public ZipFile(String fileName, String path, Charset charset, int bufferSize) throws IOException {
        File zipFile = new File(path + File.separator + fileName);
        buffer = new byte[bufferSize];
        targetFiles = new ArrayList<File>();
        zipOutputStream = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)), charset);
    }

    public void addFile(String filePath) {
        targetFiles.add(new File(filePath));
    }

    public void build() {
        writeFiles(targetFiles.toArray(new File[0]));
    }

    private void writeFiles(File[] files) {
        for (File file : files) {
            if (file.isDirectory()) {
                writeFiles(file.listFiles());
            } else {
                try {
                    ZipEntry entry = new ZipEntry(file.getPath().replace('\\', '/'));
                    zipOutputStream.putNextEntry(entry);
                    try (InputStream is = new BufferedInputStream(new FileInputStream(file))) {
                        int readLength = 0;
                        while (0 < (readLength = is.read(buffer))) {
                            zipOutputStream.write(buffer, 0, readLength);
                        }
                    }
                } catch (IOException ioe) {
                    throw new RuntimeException("", ioe);
                }
            }
        }
    }

    @Override
    public void close() throws IOException {
        zipOutputStream.close();
    }
}
Main.java
package com.uskey512;

import java.io.IOException;
import java.nio.charset.Charset;

public class Main {

    public static void main(String[] args) {
        // try (ZipFile zipFile = new ZipFile("packed.zip", ".") { // 化ける
        try (ZipFile zipFile = new ZipFile("packed.zip", ".", Charset.forName("Shift-JIS"))) { // 化けない
            zipFile.addFile(args[0]);
            zipFile.build();
        } catch (IOException ioe) {
        }
    }
}
4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5