package com.compomics.util.io.compression; import com.compomics.util.waiting.WaitingHandler; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.Enumeration; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; /** * Convenience class for the handling of zip files. * * @author Marc Vaudel * @author Harald Barsnes */ public class ZipUtils { /** * The buffer size. */ private static final int BUFFER = 2048; /** * Zips a file. * * @param originFile the file to zip, can be a folder * @param destinationFile the destination file * * @throws IOException if an IOException occurs */ public static void zip(File originFile, File destinationFile) throws IOException { zip(originFile, destinationFile, null, 0); } /** * Zips a file. * * @param originFile the file to zip, can be a folder * @param destinationFile the destination file * @param waitingHandler a waiting handler allowing canceling the process * (can be null) * @param totalUncompressedFileSize the total uncompressed size, a value * less than 0 will result in an indeterminate progress bar * * @throws IOException if an IOException occurs */ public static void zip(File originFile, File destinationFile, WaitingHandler waitingHandler, long totalUncompressedFileSize) throws IOException { FileOutputStream fos = new FileOutputStream(destinationFile); try { BufferedOutputStream bos = new BufferedOutputStream(fos); try { ZipOutputStream out = new ZipOutputStream(bos); try { addToZip(originFile, out, waitingHandler, totalUncompressedFileSize); } finally { out.close(); } } finally { bos.close(); } } finally { fos.close(); } } /** * Adds a new file to the zip stream. If the file is a folder it will be * added with its content. * * @param file the file to add to the zip * @param out the zip stream * * @throws FileNotFoundException if a FileNotFoundException occurs * @throws IOException if an IOException occurs */ public static void addToZip(File file, ZipOutputStream out) throws IOException { addToZip(file, out, null, 0); } /** * Adds a new file to the zip stream. If the file is a folder it will be * added with its content. * * @param file the file to add to the zip * @param out the zip stream * @param waitingHandler a waiting handler allowing canceling the process * (can be null) * @param totalUncompressedFileSize the total uncompressed size, a value * less than 0 will result in an indeterminate progress bar * * @throws FileNotFoundException if a FileNotFoundException occurs * @throws IOException if an IOException occurs */ public static void addToZip(File file, ZipOutputStream out, WaitingHandler waitingHandler, long totalUncompressedFileSize) throws IOException { addToZip(file, "", out, waitingHandler, totalUncompressedFileSize); } /** * Adds a new file to the zip stream. If the file is a folder it will be * added with its content. * * @param subDirectory the subdirectory relative to the zip file location * (e.g. "data", note that there is no tailing "/") * @param file the file to add to the zip * @param out the zip stream * * @throws FileNotFoundException if a FileNotFoundException occurs * @throws IOException if an IOException occurs */ public static void addToZip(File file, String subDirectory, ZipOutputStream out) throws IOException { addToZip(file, subDirectory, out, null, 0); } /** * Adds a new file to the zip stream. If the file is a folder it will be * added with its content. * * @param subDirectory the subdirectory relative to the zip file location * (e.g. "data", note that there is no tailing "/") * @param file the file to add to the zip * @param out the zip stream * @param waitingHandler a waiting handler allowing canceling the process * (can be null) * @param totalUncompressedFileSize the total uncompressed size, a value * less than 0 will result in an indeterminate progress bar * * @throws FileNotFoundException if a FileNotFoundException occurs * @throws IOException if an IOException occurs */ public static void addToZip(File file, String subDirectory, ZipOutputStream out, WaitingHandler waitingHandler, long totalUncompressedFileSize) throws IOException { if (file.isDirectory()) { String directory = subDirectory; if (!subDirectory.equals("")) { directory += "/"; } directory += file.getName(); addFolderToZip(directory, out); for (File subFile : file.listFiles()) { addToZip(subFile, subDirectory, out, waitingHandler, totalUncompressedFileSize); } } else { addFileToZip(subDirectory, file, out, waitingHandler, totalUncompressedFileSize); } } /** * Adds a new file to the zip stream. The file should not be a folder. * * @param file the file to add to the zip * @param out the zip stream * @param waitingHandler a waiting handler allowing canceling the process * (can be null) * @param totalUncompressedFileSize the total uncompressed size, a value * less than 0 will result in an indeterminate progress bar * * @throws FileNotFoundException if a FileNotFoundException occurs * @throws IOException if an IOException occurs */ public static void addFileToZip(File file, ZipOutputStream out, WaitingHandler waitingHandler, long totalUncompressedFileSize) throws IOException { addFileToZip("", file, out, waitingHandler, totalUncompressedFileSize); } /** * Adds a new file to the zip stream. The file should not be a folder. * * @param subDirectory the subdirectory relative to the zip file location * (e.g. "data", note that there is no tailing "/") * @param file the file to add to the zip * @param out the zip stream * @param waitingHandler a waiting handler allowing canceling the process * (can be null) * @param totalUncompressedFileSize the total uncompressed size, a value * less than 0 will result in an indeterminate progress bar * * @throws FileNotFoundException if a FileNotFoundException occurs * @throws IOException if an IOException occurs */ public static void addFileToZip(String subDirectory, File file, ZipOutputStream out, WaitingHandler waitingHandler, long totalUncompressedFileSize) throws IOException { if (file.isDirectory()) { throw new IllegalArgumentException("Attempting to add a folder as a file. Use addToZip instead."); } FileInputStream fi = new FileInputStream(file); try { BufferedInputStream origin = new BufferedInputStream(fi, BUFFER); try { String entryName = subDirectory; if (!subDirectory.equals("")) { entryName += "/"; } entryName += file.getName(); ZipEntry entry = new ZipEntry(entryName); out.putNextEntry(entry); byte data[] = new byte[BUFFER]; int count; long write = 0; int previousProgress = 0; if (waitingHandler != null) { previousProgress = waitingHandler.getSecondaryProgressCounter(); } while ((count = origin.read(data, 0, BUFFER)) != -1) { if (waitingHandler != null) { if (waitingHandler.isRunCanceled()) { return; } if (totalUncompressedFileSize > 0) { write += count; int progress = (int) (100.0 * write / totalUncompressedFileSize) + previousProgress; if (progress > 100) { waitingHandler.setSecondaryProgressCounterIndeterminate(true); } else { waitingHandler.setSecondaryProgressCounter(progress); } } else { waitingHandler.setSecondaryProgressCounterIndeterminate(true); } } out.write(data, 0, count); } } finally { origin.close(); } } finally { fi.close(); } } /** * Adds a new entry to the zip file corresponding to a new folder. * * @param folderPath the path to the folder relative to the zip file (e.g. * "data", note that there is no tailing "/") * @param out the zip stream * * @throws IOException if an IOException occurs */ public static void addFolderToZip(String folderPath, ZipOutputStream out) throws IOException { out.putNextEntry(new ZipEntry(folderPath + "/")); } /** * Unzips the content of an archive into a given folder. The folder needs to * exist. * * @param zipFile the file to unzip * @param destinationFolder the destination folder * @param waitingHandler a waiting handler displaying progress and allowing * canceling the process (can be null) * * @throws IOException if an IOException occurs */ public static void unzip(File zipFile, File destinationFolder, WaitingHandler waitingHandler) throws IOException { if (waitingHandler != null) { waitingHandler.setSecondaryProgressCounterIndeterminate(false); waitingHandler.setSecondaryProgressCounter(0); waitingHandler.setMaxSecondaryProgressCounter(100); } FileInputStream fi = new FileInputStream(zipFile); boolean isWindowsPlatform = (System.getProperty("os.name").lastIndexOf("Windows") == -1); try { BufferedInputStream bis = new BufferedInputStream(fi, BUFFER); try { ZipInputStream zis = new ZipInputStream(bis); try { // find the total size if all the uncompressed files long fileLength = 0; ZipFile tempZipFile = new ZipFile(zipFile); for (Enumeration<? extends ZipEntry> e = tempZipFile.entries(); e.hasMoreElements();) { ZipEntry ze = e.nextElement(); fileLength += ze.getSize(); } byte data[] = new byte[BUFFER]; long read = 0; ZipEntry entry; while ((entry = zis.getNextEntry()) != null) { String entryName = entry.getName(); // dirty fix to be able to open windows files on linux/mac and the other way around if (isWindowsPlatform) { entryName = entryName.replaceAll("\\\\", "/"); } else { entryName = entryName.replaceAll("/", "\\\\"); } File destinationFile = new File(destinationFolder, entryName); File entryFolder = destinationFile.getParentFile(); if (entry.isDirectory()) { destinationFile.mkdirs(); } else if (entryFolder.exists() || entryFolder.mkdirs()) { FileOutputStream fos = new FileOutputStream(destinationFile); try { BufferedOutputStream bos = new BufferedOutputStream(fos); try { int count; while ((count = zis.read(data, 0, BUFFER)) != -1) { bos.write(data, 0, count); if (waitingHandler != null) { if (waitingHandler.isRunCanceled()) { return; } if (fileLength > 0) { read += count; int progress = (int) (100.0 * read / fileLength); if (progress > 100) { waitingHandler.setSecondaryProgressCounterIndeterminate(true); } else { waitingHandler.setSecondaryProgressCounter(progress); } } } } } finally { bos.close(); } } finally { fos.close(); } } else { throw new IOException("Folder " + destinationFolder.getAbsolutePath() + " does not exist and could not be created. " + "Verify that you have the right to write in this directory."); } if (waitingHandler != null && waitingHandler.isRunCanceled()) { break; } } } finally { zis.close(); } } finally { bis.close(); } } finally { fi.close(); } } }