package jane.tool; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; import java.util.HashSet; import java.util.zip.Deflater; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; import jane.core.Util; /** * 合并N个jar文件成一个新的jar文件 * 如果遇到同路径文件名,则以后面指定的jar为准,空目录会被忽略 * 一般用于给出原版jar和补丁jar,合并成新版jar * 也可用于zip格式 */ public final class MergeJars { public static void mergeJars(String[] jarNames, int[] counts, PrintStream osLog) throws IOException { int count0 = 0, count1 = 0; HashSet<String> mergedPathes = new HashSet<>(); byte[] buf = new byte[0x10000]; osLog.println("= " + jarNames[jarNames.length - 1]); try(ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(jarNames[jarNames.length - 1])))) { zos.setMethod(ZipOutputStream.DEFLATED); zos.setLevel(Deflater.BEST_COMPRESSION); for(int i = jarNames.length - 2; i >= 0; --i) { osLog.println("+ " + jarNames[i]); try(ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(jarNames[i])))) { for(ZipEntry ze; (ze = zis.getNextEntry()) != null;) { if(!ze.isDirectory()) ++count0; if(mergedPathes.contains(ze.getName())) continue; mergedPathes.add(ze.getName()); if(ze.isDirectory()) { zos.putNextEntry(new ZipEntry(ze.getName())); zos.closeEntry(); continue; } int len = (int)ze.getSize(); if(len < 0) continue; if(len > buf.length) buf = new byte[len]; Util.readStream(zis, ze.getName(), buf, len); zos.putNextEntry(new ZipEntry(ze.getName())); zos.write(buf, 0, len); zos.closeEntry(); ++count1; } } } } if(counts != null && counts.length >= 2) { counts[0] = count0; counts[1] = count1; } } public static void main(String[] args) throws Exception { if(args.length < 2) { System.err.println("USAGE: java -cp jane-core.jar jane.tool.MergeJars <file1.jar> [file2.jar ...] <merge.jar>"); return; } int[] counts = new int[2]; mergeJars(args, counts, System.out); System.out.println(String.format("done! (%d/%d files)", counts[1], counts[0])); } }