きっかけ
仕事で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
安定のひしだまさんのページでほぼ解決してしまった。。
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なるものを利用すればjarをexeファイルにできるようなのですが、客先常駐なので(
参考:https://qiita.com/bugtrap/items/15864474076767a7a957
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);
}
}
}
@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
2つのzipファイルを選択して、batファイルにドラッグアンドドロップ
ドラッグアンドドロップで展開できました。
javaファイルとbatファイル2つあるの面倒
bat内でjavaファイル作ってコンパイルしてそれ使えばいいんじゃね?
ということでやってみました。
@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
一部記号をエスケープしたら普通に出力できた。
zipファイルをドラッグアンドドロップ
展開できた。
補足
今回のソースはjava8以上にパスが通っていたら使えます。