public static void copyZipWithoutEmptyDirectories(final File inputFile, final File outputFile) throws IOException
{
final byte[] buf = new byte[0x2000];
final ZipFile inputZip = new ZipFile(inputFile);
final ZipOutputStream outputStream = new ZipOutputStream(new FileOutputStream(outputFile));
try
{
// read a the entries of the input zip file and sort them
final Enumeration<? extends ZipEntry> e = inputZip.entries();
final ArrayList<ZipEntry> sortedList = new ArrayList<ZipEntry>();
while (e.hasMoreElements()) {
final ZipEntry entry = e.nextElement();
sortedList.add(entry);
}
Collections.sort(sortedList, new Comparator<ZipEntry>()
{
public int compare(ZipEntry o1, ZipEntry o2)
{
String n1 = o1.getName(), n2 = o2.getName();
if (metaOverride(n1, n2)) {
return -1;
}
if (metaOverride(n2, n1)) {
return 1;
}
return n1.compareTo(n2);
}
// make sure that META-INF/MANIFEST.MF is always the first entry after META-INF/
private boolean metaOverride(String n1, String n2) {
return (n1.startsWith("META-INF/") && !n2.startsWith("META-INF/"))
|| (n1.equals("META-INF/MANIFEST.MF") && !n2.equals(n1) && !n2.equals("META-INF/"))
|| (n1.equals("META-INF/") && !n2.equals(n1));
}
});
// treat them again and write them in output, wenn they not are empty directories
for (int i = sortedList.size()-1; i>=0; i--)
{
final ZipEntry inputEntry = sortedList.get(i);
final String name = inputEntry.getName();
final boolean isEmptyDirectory;
if (inputEntry.isDirectory())
{
if (i == sortedList.size()-1)
{
// no item afterwards; it was an empty directory
isEmptyDirectory = true;
}
else
{
final String nextName = sortedList.get(i+1).getName();
isEmptyDirectory = !nextName.startsWith(name);
}
}
else
{
isEmptyDirectory = false;
}
if (isEmptyDirectory)
{
sortedList.remove(i);
}
}
// finally write entries in normal order
for (int i = 0; i < sortedList.size(); i++)
{
final ZipEntry inputEntry = sortedList.get(i);
final ZipEntry outputEntry = new ZipEntry(inputEntry);
outputStream.putNextEntry(outputEntry);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
final InputStream is = inputZip.getInputStream(inputEntry);
IoUtil.pipe(is, baos, buf);
is.close();
outputStream.write(baos.toByteArray());
}
} finally {
outputStream.close();
inputZip.close();
}
}