1, create a JarOutputStream based on the destination jar file;
2, loop through all entries in the source jar file, and get the InputStream from each entry;
3, create a new jar entry with the same name as the source jar entry, and put the new entry to the JarOutputStream;
4, now we have InputStream, OutputStream, and the new jar entry in place, we are ready to transfer the bits, by reading bytes from InputStream into a buffer and writing buffer content to OutputStream.
5, close the InputStream, flush the JarOutputStream, and close the jar entry. This completes the copying of one jar entry.
6, after the loop ends, all entries are copied from source jar file to destination jar file. Finally, close the JarOutputStream.
package test;A common error is:
import java.io.*;
import java.util.Enumeration;
import java.util.jar.*;
//java -cp . test.CopyZip xxx/lib/sac-1.3.jar /tmp
//
public class CopyZip {
public static void main(String[] args) throws Exception {
File sourceFileOrDir = new File(args[0]);
File destDir = new File(args[1]);
if (sourceFileOrDir.isFile()) {
copyJarFile(new JarFile(sourceFileOrDir), destDir);
} else if (sourceFileOrDir.isDirectory()) {
File[] files = sourceFileOrDir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.endsWith(".jar");
}
});
for (File f : files) {
copyJarFile(new JarFile(f), destDir);
}
}
}
public static void copyJarFile(JarFile jarFile, File destDir) throws IOException {
String fileName = jarFile.getName();
String fileNameLastPart = fileName.substring(fileName.lastIndexOf(File.separator));
File destFile = new File(destDir, fileNameLastPart);
JarOutputStream jos = new JarOutputStream(new FileOutputStream(destFile));
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
InputStream is = jarFile.getInputStream(entry);
//jos.putNextEntry(entry);
//create a new entry to avoid ZipException: invalid entry compressed size
jos.putNextEntry(new JarEntry(entry.getName()));
byte[] buffer = new byte[4096];
int bytesRead = 0;
while ((bytesRead = is.read(buffer)) != -1) {
jos.write(buffer, 0, bytesRead);
}
is.close();
jos.flush();
jos.closeEntry();
}
jos.close();
}
}
Exception in thread "main" java.util.zip.ZipException: invalid entry compressed size (expected 1665 but got 1680 bytes)It usually occurs when text file entries in the source jar file contain some non-ASCII characters such as ^I ^Z ^D ^C. Some common files are META-INF/COPYRIGHT.html, META-INF/LICENSE.txt, etc, probably because these files were created in a non-ASCII editor but saved as text files. Open them in vi or vim to see these offending characters.
at java.util.zip.ZipOutputStream.closeEntry(ZipOutputStream.java:206)
at test.CopyZip.copyJarFile(CopyZip.java:63)
at test.CopyZip.main(CopyZip.java:37)
To avoid this type of ZipException, always create a new JarEntry with the same name, and pass it to putNextEntry() method. Do not pass the existing jar entry from the source jar file to putNextEntry() method.