Java7 Zip
Java7からnioにFilesが追加されたりと諸々ファイル周りのAPIが強化されてますね。
個人的には、Zipをライブラリに頼らず、Javaだけでサクッとやりたいと思ってました。
Zip File System Provider
まぁドキュメントやらgoogle先生に助けてもらって実装出来たんですけど、
圧縮は問題なさそうですね。
SimpleFileVisitorでディレクトリを探索して、Zipに追加って感じで。
相対パスをちゃんと考えないといけないので、
変数名を分かりやすくしとかないと若干混乱します。
で、解凍なんですが、圧縮と同じような考えでいけます。
解凍のほうがコードは短くすみます。
ただ、どうにも分からなかったのが、
手動で圧縮したファイルやJavaで圧縮したZipは問題なく解凍出来たのですが、
HttpClientで取得したファイルの解凍が出来ませんでした。
InputStream in = responce.getEntityInputStream(); byte[] bytes = ByteStreams.toByteArray(in); // guava File file = new File("C:/Users/nosa/AppData/Local/Temp/temp.zip"); Files.write(file.toPath(), bytes, StandardOpenOption.CREATE);
これを解凍したかったんですが、このZipをFileSystemに食わすと
java.util.zip.ZipError: zip END header not found at com.sun.nio.zipfs.ZipFileSystem.zerror(ZipFileSystem.java:1605) at com.sun.nio.zipfs.ZipFileSystem.findEND(ZipFileSystem.java:1021) at com.sun.nio.zipfs.ZipFileSystem.initCEN(ZipFileSystem.java:1030) at com.sun.nio.zipfs.ZipFileSystem.<init>(ZipFileSystem.java:130) at com.sun.nio.zipfs.ZipFileSystemProvider.newFileSystem(ZipFileSystemProvider.java:117) at java.nio.file.FileSystems.newFileSystem(FileSystems.java:322) at java.nio.file.FileSystems.newFileSystem(FileSystems.java:272)
が発生します。
昔ながらの方法(ZipFile,ZipEntry)の方法だと解凍出来ました。(もちろん手動でも解凍出来る)
また、zip4jでも解凍出来ました。
圧縮
File zipDir = new File(dirPath); final Path zipPath = zipDir.toPath(); // 圧縮 URI zipUri = zipFile.toURI(); URI uri = new URI("jar:" + zipUri.getScheme(), zipUri.getPath(), null); Map<String, String> env = new HashMap<>(); env.put("create", "true"); env.put("encoding", "UTF-8"); try (FileSystem zipfs = FileSystems.newFileSystem(uri, env)) { for (File srcFile : zipDir.listFiles()) { if (srcFile.isDirectory()) { // ディレクトリ Files.walkFileTree(srcFile.toPath(), new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { // zipするディレクトリでのファイルの相対パス Path targetPath = zipPath.relativize(file); Files.copy(file, zipfs.getPath(targetPath.toString()), StandardCopyOption.REPLACE_EXISTING); return FileVisitResult.CONTINUE; } @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { // zipするディレクトリでのディレクトリの相対パス Path targetPath = zipPath.relativize(dir); Files.createDirectory(zipfs.getPath(targetPath.toString())); return FileVisitResult.CONTINUE; } }); } else { // ファイル Path dest = zipfs.getPath(srcFile.getName()); Files.copy(srcFile.toPath(), dest, StandardCopyOption.REPLACE_EXISTING); } } }
解凍
// 解凍 URI zipUri = zipFile.toURI(); URI uri = new URI("jar:" + zipUri.getScheme(), zipUri.getPath(), null); Map<String, String> env = new HashMap<>(); env.put("create", "false"); env.put("encoding", "UTF-8"); try (FileSystem zipfs = FileSystems.newFileSystem(uri, env)) { final Path zipRoot = zipfs.getPath("/"); Files.walkFileTree(zipRoot, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { Path targetPath = Paths.get(toDir.toString(), file.toString()); Files.copy(file, targetPath, StandardCopyOption.REPLACE_EXISTING); return FileVisitResult.CONTINUE; } @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { Path targetPath = Paths.get(toDir.toString(), dir.toString()); Files.createDirectory(targetPath); return FileVisitResult.CONTINUE; } }); }
うーん。SimpleFileVisitorの仕様は好きなんですけど原因分からず、zip4jに逃げようかと...。
Zipフォーマットを理解してからもう一度調べてみよう。
Zipが壊れてて手でも解凍出来ない、ZipFileでも解凍出来ないとかであれば、
良かったんですけど。
下記、大いに参考にさせて頂きました。
JavaSE ZIP圧縮/解凍 Java7 - @//メモ