Zip展開したかった話

## きっかけ

仕事でZIPファイルのやり取りを行った際に、ZIP作成者はMac使いでこちらはWindowsでした。
この時点でわかる人はわかると思いますが、Macではエントリー名がUTF-8でZIP化され、
Windows標準のZIP展開では日本語環境ではWindows-31j(Shift-JIS)で展開するためにエントリー名が文字化けします。
~~いまだに文字コードで苦労するとか意味わからん。~~

UTF-8に対応しているフリーソフト入れたら終わりなのですが、
客先常駐で仕事しているで勝手にダウンロードするのもあれですし、せっかくなので自分で解決してみようと思いました。


## とりあえずJavaで展開
参考：http://www.ne.jp/asahi/hishidama/home/tech/java/zip.html
安定のひしだまさんのページでほぼ解決してしまった。。


```java:ZipDecoder.java
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.zip.ZipFile;

public class ZipDecoder {

	private static final String ZIP_FILE = "C:\\temp\\ふぉるだ.zip";

	public static void main(String[] args) {
		decode(ZIP_FILE);
	}

	public static void decode(String strPath) {
		if (strPath == null || !strPath.toLowerCase().endsWith(".zip")) {
			System.out.println("Argument is not zip file.");
			return;
		}
		Path zipFilePath = Paths.get(strPath);
		String outDir = zipFilePath.toString().replace(".zip", "");
		if (Files.notExists(zipFilePath)) {
			System.out.println("Argument is not file path.");
			return;
		}
		try (ZipFile zipFile = new ZipFile(zipFilePath.toFile(), Charset.forName("UTF-8"))) {
			zipFile.stream().filter(entry -> !entry.isDirectory()).forEach(entry -> {
				Path outName = Paths.get(outDir, entry.getName());
				try {
					Files.createDirectories(outName.getParent());
				} catch (IOException e1) {
					throw new UncheckedIOException(e1);
				}
				try (InputStream is = zipFile.getInputStream(entry);
						BufferedOutputStream os = new BufferedOutputStream(Files.newOutputStream(outName))) {
					byte[] buf = new byte[1024];
					while (is.read(buf) >= 0) {
						os.write(buf);
					}
				} catch (IOException e) {
					throw new UncheckedIOException(e);
				}
			});

		} catch (IOException e) {
			throw new UncheckedIOException(e);
		}
	}
}
```

## 使いまわす

まだZIPファイルのやり取りは続くので使いまわせるように作り直します。
ファイル名は起動引数で渡すようにして、ドラッグアンドドロップで展開できるようにします。
[launch4j](http://launch4j.sourceforge.net/)なるものを利用すればjarをexeファイルにできるようなのですが、客先常駐なので（

参考：https://qiita.com/bugtrap/items/15864474076767a7a957

```java:ZipDecoder.java
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.zip.ZipFile;

public class ZipDecoder {

	public static void main(String[] args) {
		if (args.length == 0) {
			System.out.println("There are no Arguments.");
		}
		Arrays.asList(args).stream().forEach(ZipDecoder::decode);
	}

	public static void decode(String strPath) {
		if (strPath == null || !strPath.toLowerCase().endsWith(".zip")) {
			System.out.println("Argument is not zip file.");
			return;
		}
		Path zipFilePath = Paths.get(strPath);
		String outDir = zipFilePath.toString().replace(".zip", "");
		if (Files.notExists(zipFilePath)) {
			System.out.println("Argument is not file path.");
			return;
		}
		try (ZipFile zipFile = new ZipFile(zipFilePath.toFile(), Charset.forName("UTF-8"))) {
			zipFile.stream().filter(entry -> !entry.isDirectory()).forEach(entry -> {
				Path outName = Paths.get(outDir, entry.getName());
				try {
					Files.createDirectories(outName.getParent());
				} catch (IOException e1) {
					throw new UncheckedIOException(e1);
				}
				try (InputStream is = zipFile.getInputStream(entry);
						BufferedOutputStream os = new BufferedOutputStream(Files.newOutputStream(outName))) {
					byte[] buf = new byte[1024];
					while (is.read(buf) >= 0) {
						os.write(buf);
					}
				} catch (IOException e) {
					throw new UncheckedIOException(e);
				}
			});

		} catch (IOException e) {
			throw new UncheckedIOException(e);
		}
	}
}

```

```:call-decoder.bat
@echo off

rem コマンドチェック
where java 2> nul > nul || goto :notfound

java -jar ZipDecoder.jar %*

echo 展開完了しました
goto :end

:notfound
echo javaコマンドにPATHを通してください
goto :end

:end
pause
```

２つのzipファイルを選択して、batファイルにドラッグアンドドロップ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199891/d583c9cd-3334-5a8a-3dea-783c4f62f19a.png)

ドラッグアンドドロップで展開できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199891/5add3756-06ec-f99c-7066-992d5560f327.png)

## javaファイルとbatファイル２つあるの面倒

bat内でjavaファイル作ってコンパイルしてそれ使えばいいんじゃね？
ということでやってみました。

```powershell:decord.bat
@echo off

rem コマンドチェック
where java 2> nul > nul || goto :notfound

echo import java.io.BufferedOutputStream;                                                                         > ZipDecoder.java
echo import java.io.IOException;                                                                                  >> ZipDecoder.java
echo import java.io.InputStream;                                                                                  >> ZipDecoder.java
echo import java.io.UncheckedIOException;                                                                         >> ZipDecoder.java
echo import java.nio.charset.Charset;                                                                             >> ZipDecoder.java
echo import java.nio.file.Files;                                                                                  >> ZipDecoder.java
echo import java.nio.file.Path;                                                                                   >> ZipDecoder.java
echo import java.nio.file.Paths;                                                                                  >> ZipDecoder.java
echo import java.util.Arrays;                                                                                     >> ZipDecoder.java
echo import java.util.zip.ZipFile;                                                                                >> ZipDecoder.java
echo public class ZipDecoder {                                                                                    >> ZipDecoder.java
echo 	public static void main(String[] args) {                                                                  >> ZipDecoder.java
echo 		if (args.length == 0) {                                                                               >> ZipDecoder.java
echo 			System.out.println("There are no Arguments.");                                                    >> ZipDecoder.java
echo 		}                                                                                                     >> ZipDecoder.java
echo 		Arrays.asList(args).stream().forEach(ZipDecoder::decode);                                             >> ZipDecoder.java
echo 	}                                                                                                         >> ZipDecoder.java
echo 	public static void decode(String strPath) {                                                               >> ZipDecoder.java
echo 		if (strPath == null ^|^| !strPath.toLowerCase().endsWith(".zip")) {                                     >> ZipDecoder.java
echo 			System.out.println("Argument is not zip file.");                                                  >> ZipDecoder.java
echo 			return;                                                                                           >> ZipDecoder.java
echo 		}                                                                                                     >> ZipDecoder.java
echo 		Path zipFilePath = Paths.get(strPath);                                                                >> ZipDecoder.java
echo 		String outDir = zipFilePath.toString().replace(".zip", "");                                           >> ZipDecoder.java
echo 		if (Files.notExists(zipFilePath)) {                                                                   >> ZipDecoder.java
echo 			System.out.println("Argument is not file path.");                                                 >> ZipDecoder.java
echo 			return;                                                                                           >> ZipDecoder.java
echo 		}                                                                                                     >> ZipDecoder.java
echo 		try (ZipFile zipFile = new ZipFile(zipFilePath.toFile(), Charset.forName("UTF-8"))) {                 >> ZipDecoder.java
echo 			zipFile.stream().filter(entry -^> !entry.isDirectory()).forEach(entry -^> {                         >> ZipDecoder.java
echo 				Path outName = Paths.get(outDir, entry.getName());                                            >> ZipDecoder.java
echo 				try {                                                                                         >> ZipDecoder.java
echo 					Files.createDirectories(outName.getParent());                                             >> ZipDecoder.java
echo 				} catch (IOException e1) {                                                                    >> ZipDecoder.java
echo 					throw new UncheckedIOException(e1);                                                       >> ZipDecoder.java
echo 				}                                                                                             >> ZipDecoder.java
echo 				try (InputStream is = zipFile.getInputStream(entry);                                          >> ZipDecoder.java
echo 						BufferedOutputStream os = new BufferedOutputStream(Files.newOutputStream(outName))) { >> ZipDecoder.java
echo 					byte[] buf = new byte[1024];                                                              >> ZipDecoder.java
echo 					while (is.read(buf) ^>= 0) {                                                               >> ZipDecoder.java
echo 						os.write(buf);                                                                        >> ZipDecoder.java
echo 					}                                                                                         >> ZipDecoder.java
echo 				} catch (IOException e) {                                                                     >> ZipDecoder.java
echo 					throw new UncheckedIOException(e);                                                        >> ZipDecoder.java
echo 				}                                                                                             >> ZipDecoder.java
echo 			});                                                                                               >> ZipDecoder.java
echo 		} catch (IOException e) {                                                                             >> ZipDecoder.java
echo 			throw new UncheckedIOException(e);                                                                >> ZipDecoder.java
echo 		}                                                                                                     >> ZipDecoder.java
echo 	}                                                                                                         >> ZipDecoder.java
echo }                                                                                                            >> ZipDecoder.java

javac ZipDecoder.java

java ZipDecoder %*

del ZipDecoder.java
del ZipDecoder.class

echo 展開完了しました
goto :end

:notfound
echo javaコマンドにPATHを通してください
goto :end

:end
pause
```

一部記号をエスケープしたら普通に出力できた。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199891/1c4cfde5-60bf-910f-245d-64a19f14e844.png)

zipファイルをドラッグアンドドロップ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199891/96c8ea39-d0c6-c1cc-4b4a-94a06a66275f.png)

展開できた。

## 補足

今回のソースはjava8以上にパスが通っていたら使えます。