it.greenvulcano.util.zip.ZipHelper.java Source code

Java tutorial

Introduction

Here is the source code for it.greenvulcano.util.zip.ZipHelper.java

Source

/*******************************************************************************
 * Copyright (c) 2009, 2016 GreenVulcano ESB Open Source Project.
 * All rights reserved.
 *
 * This file is part of GreenVulcano ESB.
 *
 * GreenVulcano ESB is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * GreenVulcano ESB is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with GreenVulcano ESB. If not, see <http://www.gnu.org/licenses/>.
 *******************************************************************************/
package it.greenvulcano.util.zip;

import it.greenvulcano.util.file.RegExFilenameFilter;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.zip.Deflater;
import java.util.zip.Inflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;

/**
 * ZipHelper class
 *
 * @version 3.0.0 Feb 17, 2010
 * @author GreenVulcano Developer Team
 *
 *
 */
public class ZipHelper {
    /**
     * Compression level for best compression.
     */
    public static final String BEST_COMPRESSION_S = "best-compression";
    /**
     * Compression level for fastest compression.
     */
    public static final String BEST_SPEED_S = "best-speed";
    /**
     * Default compression level.
     */
    public static final String DEFAULT_COMPRESSION_S = "default-compression";
    /**
     * Compression level for no compression.
     */
    public static final String NO_COMPRESSION_S = "no-compression";
    /**
     * Compression level for best compression.
     */
    public static final int BEST_COMPRESSION = Deflater.BEST_COMPRESSION;
    /**
     * Compression level for fastest compression.
     */
    public static final int BEST_SPEED = Deflater.BEST_SPEED;
    /**
     * Default compression level.
     */
    public static final int DEFAULT_COMPRESSION = Deflater.DEFAULT_COMPRESSION;
    /**
     * Compression level for no compression.
     */
    public static final int NO_COMPRESSION = Deflater.NO_COMPRESSION;
    /**
     * Default inflating temporary buffer size.
     */
    private static final int DEFAULT_SIZE = 1024;

    /**
     * Compression level
     */
    private int compressionLevel = BEST_SPEED;
    /**
     * Compresser instance
     */
    private Deflater compresser = null;
    /**
     * Decompresser instance
     */
    private Inflater decompresser = null;
    /**
     * Map for compression level
     */
    private static HashMap<String, Integer> cLevelMap = null;

    static {
        if (cLevelMap == null) {
            cLevelMap = new HashMap<String, Integer>();
            cLevelMap.put(BEST_COMPRESSION_S, Integer.valueOf(BEST_COMPRESSION));
            cLevelMap.put(BEST_SPEED_S, Integer.valueOf(BEST_SPEED));
            cLevelMap.put(DEFAULT_COMPRESSION_S, Integer.valueOf(DEFAULT_COMPRESSION));
            cLevelMap.put(NO_COMPRESSION_S, Integer.valueOf(NO_COMPRESSION));
        }
    }

    /**
     * Constructor
     *
     * Create a ZipHelper with default values.
     */
    public ZipHelper() {
        // do nothing
    }

    /**
     * Set the compression level to use.
     *
     * @param cLevel
     *        the compression level to use
     * @exception ZipHelperException
     *            if error occurs
     */
    public void setCompressionLevel(int cLevel) throws ZipHelperException {
        if ((cLevel != DEFAULT_COMPRESSION) && (cLevel != BEST_COMPRESSION) && (cLevel != BEST_SPEED)
                && (cLevel != NO_COMPRESSION)) {
            throw new ZipHelperException("Invalid compression level: " + cLevel);
        }
        compressionLevel = cLevel;
    }

    /**
     * Set the compression level to use.
     *
     * @param cLevel
     *        the compression level to use
     * @exception ZipHelperException
     *            if error occurs
     */
    public void setCompressionLevel(String cLevel) throws ZipHelperException {
        Integer iLevel = cLevelMap.get(cLevel);
        if (iLevel == null) {
            throw new ZipHelperException("Invalid compression level: " + cLevel);
        }
        compressionLevel = iLevel.intValue();
    }

    /**
     * Compress the input buffer.
     *
     * @param input
     *        the data to compress
     * @return the compressed data
     * @throws ZipHelperException
     *         if error occurs
     */
    public byte[] zip(byte[] input) throws ZipHelperException {
        try {
            if (compresser == null) {
                compresser = new Deflater(compressionLevel, true);
            }

            byte[] output = new byte[input.length];
            ByteArrayOutputStream outstream = new ByteArrayOutputStream(input.length);
            compresser.setInput(input);
            compresser.finish();
            while (!compresser.needsInput()) {
                int compressedDataLength = compresser.deflate(output, 0, output.length);
                if (compressedDataLength > 0) {
                    outstream.write(output, 0, compressedDataLength);
                }
            }
            if (!compresser.finished()) {
                int compressedDataLength = compresser.deflate(output, 0, output.length);
                if (compressedDataLength > 0) {
                    outstream.write(output, 0, compressedDataLength);
                }
            }
            return outstream.toByteArray();
        } catch (Exception exc) {
            throw new ZipHelperException("Error occurred compressing data: " + exc.getMessage(), exc);
        } finally {
            if (compresser != null) {
                compresser.reset();
            }
        }
    }

    /**
     * Uncompress the input buffer.
     *
     * @param input
     *        the data to uncompress
     * @return the uncompressed data
     * @throws ZipHelperException
     *         if error occurs
     */
    public byte[] unzip(byte[] input) throws ZipHelperException {
        try {
            if (decompresser == null) {
                decompresser = new Inflater(true);
            }

            byte[] output = new byte[DEFAULT_SIZE];
            ByteArrayOutputStream outstream = new ByteArrayOutputStream(input.length);
            decompresser.setInput(input);
            while (!decompresser.needsInput()) {
                int decompressedDataLength = decompresser.inflate(output, 0, output.length);
                if (decompressedDataLength > 0) {
                    outstream.write(output, 0, decompressedDataLength);
                }
            }
            return outstream.toByteArray();
        } catch (Exception exc) {
            throw new ZipHelperException("Error occurred decompressing data: " + exc.getMessage(), exc);
        } finally {
            if (decompresser != null) {
                decompresser.reset();
            }
        }
    }

    /**
     * Performs the <code>ZIP</code> compression of a file/directory, whose name
     * and parent directory are passed as arguments, on the local filesystem.
     * The result is written into a target file with the <code>zip</code>
     * extension.<br>
     * The source filename may contain a regualr expression: in this
     * case, all the filenames matching the pattern will be compressed and put
     * in the same target <code>zip</code> file.<br>
     *
     *
     * @param srcDirectory
     *            the source parent directory of the file/s to be zipped. Must
     *            be an absolute pathname.
     * @param fileNamePattern
     *            the name of the file to be zipped. May contain a regular expression,
     *            possibly matching multiple files/directories.
     *            If matching a directory, the directory is zipped with all its content as well.
     * @param targetDirectory
     *            the target parent directory of the created <code>zip</code>
     *            file. Must be an absolute pathname.
     * @param zipFilename
     *            the name of the zip file to be created. Cannot be
     *            <code>null</code>, and must have the <code>.zip</code>
     *            extension. If a target file already exists with the same name
     *            in the same directory, it will be overwritten.
     * @throws IOException
     *             If any error occurs during file compression.
     * @throws IllegalArgumentException
     *             if the arguments are invalid.
     */
    public void zipFile(String srcDirectory, String fileNamePattern, String targetDirectory, String zipFilename)
            throws IOException {

        File srcDir = new File(srcDirectory);

        if (!srcDir.isAbsolute()) {
            throw new IllegalArgumentException(
                    "The pathname of the source parent directory is NOT absolute: " + srcDirectory);
        }

        if (!srcDir.exists()) {
            throw new IllegalArgumentException(
                    "Source parent directory " + srcDirectory + " NOT found on local filesystem.");
        }

        if (!srcDir.isDirectory()) {
            throw new IllegalArgumentException("Source parent directory " + srcDirectory + " is NOT a directory.");
        }

        File targetDir = new File(targetDirectory);

        if (!targetDir.isAbsolute()) {
            throw new IllegalArgumentException(
                    "The pathname of the target parent directory is NOT absolute: " + targetDirectory);
        }

        if (!targetDir.exists()) {
            throw new IllegalArgumentException(
                    "Target parent directory " + targetDirectory + " NOT found on local filesystem.");
        }

        if (!targetDir.isDirectory()) {
            throw new IllegalArgumentException(
                    "Target parent directory " + targetDirectory + " is NOT a directory.");
        }

        if ((zipFilename == null) || (zipFilename.length() == 0)) {
            throw new IllegalArgumentException("Target zip file name is missing.");
        }

        ZipOutputStream zos = null;
        try {
            zos = new ZipOutputStream(new FileOutputStream(new File(targetDir, zipFilename)));
            zos.setLevel(compressionLevel);

            URI base = srcDir.toURI();
            File[] files = srcDir.listFiles(new RegExFilenameFilter(fileNamePattern));

            for (File file : files) {
                internalZipFile(file, zos, base);
            }
        } finally {
            try {
                if (zos != null) {
                    zos.close();
                }
            } catch (Exception exc) {
                // Do nothing
            }
        }
    }

    /**
     * Performs the uncompression of a <code>zip</code> file, whose name and
     * parent directory are passed as arguments, on the local filesystem. The
     * content of the <code>zip</code> file will be uncompressed within a
     * specified target directory.<br>
     *
     * @param srcDirectory
     *            the source parent directory of the file/s to be unzipped. Must
     *            be an absolute pathname.
     * @param zipFilename
     *            the name of the file to be unzipped. Cannot contain wildcards.
     * @param targetDirectory
     *            the target directory in which the content of the
     *            <code>zip</code> file will be unzipped. Must be an absolute
     *            pathname.
     * @throws IOException
     *             If any error occurs during file uncompression.
     * @throws IllegalArgumentException
     *             if the arguments are invalid.
     */
    public void unzipFile(String srcDirectory, String zipFilename, String targetDirectory) throws IOException {

        File srcDir = new File(srcDirectory);

        if (!srcDir.isAbsolute()) {
            throw new IllegalArgumentException(
                    "The pathname of the source parent directory is NOT absolute: " + srcDirectory);
        }

        if (!srcDir.exists()) {
            throw new IllegalArgumentException(
                    "Source parent directory " + srcDirectory + " NOT found on local filesystem.");
        }

        if (!srcDir.isDirectory()) {
            throw new IllegalArgumentException("Source parent directory " + srcDirectory + " is NOT a directory.");
        }

        File srcZipFile = new File(srcDirectory, zipFilename);
        if (!srcZipFile.exists()) {
            throw new IllegalArgumentException(
                    "File to be unzipped (" + srcZipFile.getAbsolutePath() + ") NOT found on local filesystem.");
        }

        ZipFile zipFile = null;
        try {
            zipFile = new ZipFile(srcZipFile);
            Enumeration<? extends ZipEntry> entries = zipFile.entries();
            while (entries.hasMoreElements()) {
                ZipEntry currEntry = entries.nextElement();
                if (currEntry.isDirectory()) {
                    String targetSubdirPathname = currEntry.getName();
                    File dir = new File(targetDirectory, targetSubdirPathname);
                    FileUtils.forceMkdir(dir);
                    dir.setLastModified(currEntry.getTime());
                } else {
                    InputStream is = null;
                    OutputStream os = null;
                    File file = null;
                    try {
                        is = zipFile.getInputStream(currEntry);
                        FileUtils.forceMkdir(new File(targetDirectory, currEntry.getName()).getParentFile());
                        file = new File(targetDirectory, currEntry.getName());
                        os = new FileOutputStream(file);
                        IOUtils.copy(is, os);
                    } finally {
                        try {
                            if (is != null) {
                                is.close();
                            }

                            if (os != null) {
                                os.close();
                            }
                        } catch (IOException exc) {
                            // Do nothing
                        }

                        if (file != null) {
                            file.setLastModified(currEntry.getTime());
                        }
                    }
                }
            }
        } finally {
            try {
                if (zipFile != null) {
                    zipFile.close();
                }
            } catch (Exception exc) {
                // do nothing
            }
        }
    }

    private void internalZipFile(File srcFile, ZipOutputStream zos, URI base) throws IOException {
        String zipEntryName = base.relativize(srcFile.toURI()).getPath();
        if (srcFile.isDirectory()) {
            zipEntryName = zipEntryName.endsWith("/") ? zipEntryName : zipEntryName + "/";
            ZipEntry anEntry = new ZipEntry(zipEntryName);
            anEntry.setTime(srcFile.lastModified());
            zos.putNextEntry(anEntry);

            File[] dirList = srcFile.listFiles();
            for (File file : dirList) {
                internalZipFile(file, zos, base);
            }
        } else {
            ZipEntry anEntry = new ZipEntry(zipEntryName);
            anEntry.setTime(srcFile.lastModified());
            zos.putNextEntry(anEntry);

            FileInputStream fis = null;
            try {
                fis = new FileInputStream(srcFile);
                IOUtils.copy(fis, zos);
                zos.closeEntry();
            } finally {
                try {
                    if (fis != null) {
                        fis.close();
                    }
                } catch (IOException exc) {
                    // Do nothing
                }
            }
        }
    }
}