JarUtil.java Source code

Java tutorial

Introduction

Here is the source code for JarUtil.java

Source

//package com.qlogic.commons.utils.io;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
import java.util.zip.CRC32;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

public final class JarUtil {

    private final static boolean IS_WINDOWS = (File.separatorChar == '\\');

    /**
     * Writes all files of the given directory to the specified jar-file.
     * 
     * @param sourceDir
     *            The directory containing the "source" files.
     * @param target
     *            The jar file which should be created
     * @param compress
     *            True when the jar file should be compressed
     * @throws FileNotFoundException
     *             when a file could not be found
     * @throws IOException
     *             when a file could not be read or the jar file could not be
     *             written to.
     */
    public static void jar(File sourceDir, File target, boolean compress) throws IOException {
        jar(sourceDir, target, compress);
    }

    /**
     * Writes all given files to the specified jar-file.
     * 
     * @param files
     *            all files that should be added to the JAR file
     * @param sourceDir
     *            The parent directory containing the given files.
     * @param target
     *            The jar file which should be created
     * @param compress
     *            True when the jar file should be compressed
     * @throws FileNotFoundException
     *             when a file could not be found
     * @throws IOException
     *             when a file could not be read or the jar file could not be
     *             written to.
     */
    public static void jar(File sourceDir, OutputStream target, boolean compress) throws IOException {
        File[] files = sourceDir.listFiles();
        // creates target-jar-file:
        JarOutputStream out = new JarOutputStream(target);
        if (compress) {
            out.setLevel(ZipOutputStream.DEFLATED);
        } else {
            out.setLevel(ZipOutputStream.STORED);
        }
        // create a CRC32 object:
        CRC32 crc = new CRC32();
        byte[] buffer = new byte[1024 * 1024];
        // add all files:
        int sourceDirLength = sourceDir.getAbsolutePath().length() + 1;
        for (File file : files) {
            addFile(file, out, crc, sourceDirLength, buffer);
        }
        out.close();
    }

    /**
     * Adds one file to the given jar file. If the specified file is a
     * directory, all included files will be added.
     * 
     * @param file
     *            The file which should be added
     * @param out
     *            The jar file to which the given jar file should be added
     * @param crc
     *            A helper class for the CRC32 calculation
     * @param sourceDirLength
     *            The number of chars which can be skipped from the file's path
     * @param buffer
     *            A buffer for reading the files.
     * @throws FileNotFoundException
     *             when the file was not found
     * @throws IOException
     *             when the file could not be read or not be added
     */
    private static void addFile(File file, JarOutputStream out, CRC32 crc, int sourceDirLength, byte[] buffer)
            throws FileNotFoundException, IOException {
        if (file.isDirectory()) {
            File[] fileNames = file.listFiles();
            for (int i = 0; i < fileNames.length; i++) {
                addFile(fileNames[i], out, crc, sourceDirLength, buffer);
            }
        } else {
            String entryName = file.getAbsolutePath().substring(sourceDirLength);
            if (IS_WINDOWS) {
                entryName = entryName.replace('\\', '/');
            }
            JarEntry entry = new JarEntry(entryName);
            // read file:
            FileInputStream in = new FileInputStream(file);
            add(entry, in, out, crc, buffer);
        }
    }

    /**
     * @param entry
     * @param in
     * @param out
     * @param crc
     * @param buffer
     * @throws IOException
     */
    private static void add(JarEntry entry, InputStream in, JarOutputStream out, CRC32 crc, byte[] buffer)
            throws IOException {
        out.putNextEntry(entry);
        int read;
        long size = 0;
        while ((read = in.read(buffer)) != -1) {
            crc.update(buffer, 0, read);
            out.write(buffer, 0, read);
            size += read;
        }
        entry.setCrc(crc.getValue());
        entry.setSize(size);
        in.close();
        out.closeEntry();
        crc.reset();
    }

    /**
     * Adds the given file to the specified JAR file.
     * 
     * @param file
     *            the file that should be added
     * @param jarFile
     *            The JAR to which the file should be added
     * @param parentDir
     *            the parent directory of the file, this is used to calculate
     *            the path witin the JAR file. When null is given, the file will
     *            be added into the root of the JAR.
     * @param compress
     *            True when the jar file should be compressed
     * @throws FileNotFoundException
     *             when the jarFile does not exist
     * @throws IOException
     *             when a file could not be written or the jar-file could not
     *             read.
     */
    public static void addToJar(File file, File jarFile, File parentDir, boolean compress)
            throws FileNotFoundException, IOException {
        File tmpJarFile = File.createTempFile("tmp", ".jar", jarFile.getParentFile());
        JarOutputStream out = new JarOutputStream(new FileOutputStream(tmpJarFile));
        if (compress) {
            out.setLevel(ZipOutputStream.DEFLATED);
        } else {
            out.setLevel(ZipOutputStream.STORED);
        }
        // copy contents of old jar to new jar:
        JarFile inputFile = new JarFile(jarFile);
        JarInputStream in = new JarInputStream(new FileInputStream(jarFile));
        CRC32 crc = new CRC32();
        byte[] buffer = new byte[512 * 1024];
        JarEntry entry = (JarEntry) in.getNextEntry();
        while (entry != null) {
            InputStream entryIn = inputFile.getInputStream(entry);
            add(entry, entryIn, out, crc, buffer);
            entryIn.close();
            entry = (JarEntry) in.getNextEntry();
        }
        in.close();
        inputFile.close();

        int sourceDirLength;
        if (parentDir == null) {
            sourceDirLength = file.getAbsolutePath().lastIndexOf(File.separatorChar) + 1;
        } else {
            sourceDirLength = file.getAbsolutePath().lastIndexOf(File.separatorChar) + 1
                    - parentDir.getAbsolutePath().length();
        }
        addFile(file, out, crc, sourceDirLength, buffer);
        out.close();

        // remove old jar file and rename temp file to old one:
        if (jarFile.delete()) {
            if (!tmpJarFile.renameTo(jarFile)) {
                throw new IOException(
                        "Unable to rename temporary JAR file to [" + jarFile.getAbsolutePath() + "].");
            }
        } else {
            throw new IOException("Unable to delete old JAR file [" + jarFile.getAbsolutePath() + "].");
        }

    }

    /**
     * Extracts the given jar-file to the specified directory. The target
     * directory will be cleaned before the jar-file will be extracted.
     * 
     * @param jarFile
     *            The jar file which should be unpacked
     * @param targetDir
     *            The directory to which the jar-content should be extracted.
     * @throws FileNotFoundException
     *             when the jarFile does not exist
     * @throws IOException
     *             when a file could not be written or the jar-file could not
     *             read.
     */
    public static void unjar(File jarFile, File targetDir) throws FileNotFoundException, IOException {
        // clear target directory:
        if (targetDir.exists()) {
            targetDir.delete();
        }
        // create new target directory:
        targetDir.mkdirs();
        // read jar-file:
        String targetPath = targetDir.getAbsolutePath() + File.separatorChar;
        byte[] buffer = new byte[1024 * 1024];
        JarFile input = new JarFile(jarFile, false, ZipFile.OPEN_READ);
        Enumeration<JarEntry> enumeration = input.entries();
        for (; enumeration.hasMoreElements();) {
            JarEntry entry = enumeration.nextElement();
            if (!entry.isDirectory()) {
                // do not copy anything from the package cache:
                if (entry.getName().indexOf("package cache") == -1) {
                    String path = targetPath + entry.getName();
                    File file = new File(path);
                    if (!file.getParentFile().exists()) {
                        file.getParentFile().mkdirs();
                    }
                    FileOutputStream out = new FileOutputStream(file);
                    InputStream in = input.getInputStream(entry);
                    int read;
                    while ((read = in.read(buffer)) != -1) {
                        out.write(buffer, 0, read);
                    }
                    in.close();
                    out.close();
                }
            }
        }

    }

    /**
     * Extracts the given resource from a jar-file to the specified directory.
     * 
     * @param jarFile
     *            The jar file which should be unpacked
     * @param resource
     *            The name of a resource in the jar
     * @param targetDir
     *            The directory to which the jar-content should be extracted.
     * @throws FileNotFoundException
     *             when the jarFile does not exist
     * @throws IOException
     *             when a file could not be written or the jar-file could not
     *             read.
     */
    public static void unjar(File jarFile, String resource, File targetDir)
            throws FileNotFoundException, IOException {
        // clear target directory:
        if (targetDir.exists()) {
            targetDir.delete();
        }
        // create new target directory:
        targetDir.mkdirs();
        // read jar-file:
        String targetPath = targetDir.getAbsolutePath() + File.separatorChar;
        byte[] buffer = new byte[1024 * 1024];
        JarFile input = new JarFile(jarFile, false, ZipFile.OPEN_READ);
        Enumeration<JarEntry> enumeration = input.entries();
        for (; enumeration.hasMoreElements();) {
            JarEntry entry = enumeration.nextElement();
            if (!entry.isDirectory()) {
                // do not copy anything from the package cache:
                if (entry.getName().equals(resource)) {
                    String path = targetPath + entry.getName();
                    File file = new File(path);
                    if (!file.getParentFile().exists()) {
                        file.getParentFile().mkdirs();
                    }
                    FileOutputStream out = new FileOutputStream(file);
                    InputStream in = input.getInputStream(entry);
                    int read;
                    while ((read = in.read(buffer)) != -1) {
                        out.write(buffer, 0, read);
                    }
                    in.close();
                    out.close();
                }
            }
        }
    }

    /**
     * Reads the package-names from the given jar-file.
     * 
     * @param jarFile
     *            the jar file
     * @return an array with all found package-names
     * @throws IOException
     *             when the jar-file could not be read
     */
    public static String[] getPackageNames(File jarFile) throws IOException {
        HashMap<String, String> packageNames = new HashMap<String, String>();
        JarFile input = new JarFile(jarFile, false, ZipFile.OPEN_READ);
        Enumeration<JarEntry> enumeration = input.entries();
        for (; enumeration.hasMoreElements();) {
            JarEntry entry = enumeration.nextElement();
            String name = entry.getName();
            if (name.endsWith(".class")) {
                int endPos = name.lastIndexOf('/');
                boolean isWindows = false;
                if (endPos == -1) {
                    endPos = name.lastIndexOf('\\');
                    isWindows = true;
                }
                name = name.substring(0, endPos);
                name = name.replace('/', '.');
                if (isWindows) {
                    name = name.replace('\\', '.');
                }
                packageNames.put(name, name);
            }
        }
        return (String[]) packageNames.values().toArray(new String[packageNames.size()]);
    }

}