先日、tar and gzip 圧縮・展開を書いたので、ZIP圧縮・展開です。これは Apache commons-compress を必要とすることなく
標準ライブラリと、Throwable な Consumerがあれば綺麗に書けます。→ ラムダ式の例外処理を綺麗にする - Oboe吹きプログラマの黙示録
圧縮サンプル ・・・Throwable な Consumer → ThrowableConsumer.of を使います。
List<String> files = /* 圧縮対象のファイルのエントリPATH のリスト */ try(ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File("out/test.zip")))){ files.stream().forEach(ThrowableConsumer.of(e->{ File f = new File(e); if (f.exists()){ zos.putNextEntry(new ZipEntry(f.isDirectory() ? e + "/" : e)); if (f.isFile()){ try(FileInputStream fis = new FileInputStream(e); BufferedInputStream bis = new BufferedInputStream(fis)){ int size = 0; byte[] buf = new byte[1024]; while((size = bis.read(buf)) > 0){ zos.write(buf, 0, size); } } } } })); }catch(Exception ex){ ex.printStackTrace(); }
展開サンプル、展開時にエントリ名を標準出力してます。
try(ZipInputStream zin = new ZipInputStream(new FileInputStream("out/test.zip"))){ ZipEntry entry; while((entry = zin.getNextEntry()) != null){ System.out.println( entry.getName() ); if (entry.isDirectory()){ String s = entry.getName(); new File(dirPath + "/" + s.substring(0, s.length()-1)).mkdir(); }else{ String[] d = entry.getName().split("/"); String dir = dirPath; for(int i=0;i < d.length-1;i++){ dir += "/" + d[i]; new File(dir).mkdir(); } try(FileOutputStream fos = new FileOutputStream(dirPath+"/"+entry.getName()); BufferedOutputStream bos = new BufferedOutputStream(fos)){ int size = 0; byte[] buf = new byte[1024]; while((size = zin.read(buf)) > 0){ bos.write(buf, 0, size); } } } } }catch(Exception ex){ ex.printStackTrace(); }
tar and gzip のケースのように、
tar and gzip 圧縮・展開を補強 - Oboe吹きプログラマの黙示録
ディレクトリscan を合わせて、
oboe2uran.hatenablog.com
1つのインターフェースとしてまとめておきたくなりました。
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.util.ArrayList; import java.util.Collection; import java.util.Set; import java.util.TreeSet; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; import org.yipuran.function.ThrowableConsumer; /** * ZIP 圧縮/解凍プロセッサ. * (規則) * ZIPファイル名拡張子 → .zip * (圧縮) * Supplier<Collection<FileCollection>> = ファイルコレクション(FileCollection)で指定する対象を * Collection<String> compress(String targzPath) で圧縮する。 * メソッド戻り値は、tarエントリ名 Collection * (展開) * void decompress(String zipPath, String dirPath) で展開する。 * @since 1.1 */ public interface ZipProcessor extends Supplier<Collection<FileCollection>>{ /** * ZIP 圧縮実行. * <PRE> * Supplier で渡す FileCollection の渡し方で単一か複数か決まる。 * 例1) * // targetPath配下を圧縮対象にする場合 * List<FileCollection> fileCollections = * Arrays.stream(new File(targetPath).listFiles()).map(e->FileCollection.of(e.getAbsolutePath())).collect(Collectors.toList()); * ZipProcessor processor = ()->fileCollections; * Collection<String> entries = processor.compress(zipPath); * * 例2) * // 1つのディレクトリツリーで圧縮 * FileCollection fileCollection = FileCollection.of(targetPath); * ZipProcessor processor = ()->Arrays.asList(fileCollection); * Collection<String> entries = processor.compress(zipPath); * * </PRE> * @param zipPath 作成する ZIPファイルパス、 *.zip * @return ZIPエントリ名 Collection */ public default Collection<String> compress(String zipPath){ Collection<String> entries = new ArrayList<>(); try(ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File(zipPath)))){ get().forEach(fc->{ String prefix = fc.getFile().getParentFile().getAbsolutePath().replaceAll("\\\\", "/"); fc.scan(ThrowableConsumer.of(f->{ String entryName = f.getAbsolutePath().replaceAll("\\\\", "/").replaceFirst(prefix, ""); ZipEntry entry = new ZipEntry(f.isDirectory() ? entryName + "/" : entryName); entries.add(entry.getName().charAt(0)=='/' ? entry.getName().substring(1) : entry.getName()); zos.putNextEntry(entry); if (f.isFile()){ try(FileInputStream fis = new FileInputStream(f); BufferedInputStream bis = new BufferedInputStream(fis)){ int size = 0; byte[] buf = new byte[1024]; while((size = bis.read(buf)) > 0){ zos.write(buf, 0, size); } } } })); }); }catch(IOException ex){ throw new RuntimeException(ex); } return entries; } /** * zip 圧縮実行(対象制限). * <PRE> * Predicate<File> で、tar作成対象を制限する。任意ディレクトリパスなど制限するために使用する。 * </PRE> * @param zipPath 作成する zip ファイルパス、 *.zip * @param p Predicate<File>制限規則の付与 * @return ZIPエントリ名 Collection */ public default Collection<String> compress(String zipPath, Predicate<File> p){ Collection<String> entries = new ArrayList<>(); try(ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File(zipPath)))){ get().forEach(fc->{ String prefix = fc.getFile().getParentFile().getAbsolutePath().replaceAll("\\\\", "/"); fc.scan(p, ThrowableConsumer.of(f->{ String entryName = f.getAbsolutePath().replaceAll("\\\\", "/").replaceFirst(prefix, ""); ZipEntry entry = new ZipEntry(f.isDirectory() ? entryName + "/" : entryName); entries.add(entry.getName().charAt(0)=='/' ? entry.getName().substring(1) : entry.getName()); zos.putNextEntry(entry); if (f.isFile()){ try(FileInputStream fis = new FileInputStream(f); BufferedInputStream bis = new BufferedInputStream(fis)){ int size = 0; byte[] buf = new byte[1024]; while((size = bis.read(buf)) > 0){ zos.write(buf, 0, size); } } } })); }); }catch(IOException ex){ throw new RuntimeException(ex); } return entries; } /** * ZIPファイル展開. * @param zipPath ZIPファイルパス * @param dirPath 展開先ディレクトリパス * @return Set<String> ZIPエントリ名 Collection */ public static Set<String> decompress(String zipPath, String dirPath){ TreeSet<String> entries = new TreeSet<>(); // 展開 try(ZipInputStream zin = new ZipInputStream(new FileInputStream(zipPath))){ ZipEntry entry; while((entry = zin.getNextEntry()) != null){ entries.add(entry.getName()); if (entry.isDirectory()){ String s = entry.getName(); new File(dirPath + "/" + s.substring(0, s.length()-1)).mkdir(); }else{ String[] d = entry.getName().split("/"); String dir = dirPath; for(int i=0;i < d.length-1;i++){ dir += "/" + d[i]; new File(dir).mkdir(); } try(FileOutputStream fos = new FileOutputStream(dirPath+"/"+entry.getName()); BufferedOutputStream bos = new BufferedOutputStream(fos)){ int size = 0; byte[] buf = new byte[1024]; while((size = zin.read(buf)) > 0){ bos.write(buf, 0, size); } } } } }catch(IOException ex){ throw new RuntimeException(ex.getMessage(), ex); } return entries; } /** * エントリ名コレクション. * @param zipPath ZIPファイルパス、 *.zip * @return Set<String> ZIPエントリ名 Collection */ public static Set<String> viewPath(String zipPath){ TreeSet<String> entries = new TreeSet<>(); try(ZipInputStream zin = new ZipInputStream(new FileInputStream(zipPath))){ ZipEntry entry; while((entry = zin.getNextEntry()) != null){ entries.add(entry.getName()); } }catch(IOException ex){ throw new RuntimeException(ex.getMessage(), ex); } return entries; } }
Java8 です。