2012年7月2日 星期一

How to compress(zip) a folder and keep original folder structure using java

如何用 java 壓縮(zip)一個目錄
How to compress(zip) a folder and keep original folder structure  using java

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.util.Enumeration;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.apache.commons.compress.utils.IOUtils;

/**
 * Utility to Zip and Unzip nested directories recursively.
 * @author 
 */
public class ZipUtil {

    /**
     * Creates a zip file at the specified path with the contents of the specified directory.
     * NB:
     *
     * @param directoryPath The path of the directory where the archive will be created. eg. c:/temp
     * @param zipPath The full path of the archive to create. eg. c:/temp/archive.zip
     * @throws IOException If anything goes wrong
     */
    public static void createZip(String directoryPath, String zipPath) throws IOException {
        FileOutputStream fOut = null;
        BufferedOutputStream bOut = null;
        ZipArchiveOutputStream tOut = null;

        try {
            fOut = new FileOutputStream(new File(zipPath));
            bOut = new BufferedOutputStream(fOut);
            tOut = new ZipArchiveOutputStream(bOut);
            addFileToZip(tOut, directoryPath, "");
        } finally {
            tOut.finish();
            tOut.close();
            bOut.close();
            fOut.close();
        }

    }

    /**
     * Creates a zip entry for the path specified with a name built from the base passed in and the file/directory
     * name. If the path is a directory, a recursive call is made such that the full directory is added to the zip.
     *
     * @param zOut The zip file's output stream
     * @param path The filesystem path of the file/directory being added
     * @param base The base prefix to for the name of the zip file entry
     *
     * @throws IOException If anything goes wrong
     */
    private static void addFileToZip(ZipArchiveOutputStream zOut, String path, String base) throws IOException {
        File f = new File(path);
        String entryName = base + f.getName();
        ZipArchiveEntry zipEntry = new ZipArchiveEntry(f, entryName);
        
        zOut.putArchiveEntry(zipEntry);
        System.err.println(f.getAbsolutePath());
        if (f.isFile()) {
        if(f.getName().indexOf("7z")>0){
        IOUtils.copy(new FileInputStream(f), zOut);
        zOut.closeArchiveEntry();
        }
        } else {
            zOut.closeArchiveEntry();
            File[] children = f.listFiles();

            if (children != null) {
                for (File child : children) {
                    addFileToZip(zOut, child.getAbsolutePath(), entryName + "/");
                }
            }
        }
    }

    /**
     * Extract zip file at the specified destination path. 
     * NB:archive must consist of a single root folder containing everything else
     * 
     * @param archivePath path to zip file
     * @param destinationPath path to extract zip file to. Created if it doesn't exist.
     */
    public static void extractZip(String archivePath, String destinationPath) {
        File archiveFile = new File(archivePath);
        File unzipDestFolder = null;

        try {
            unzipDestFolder = new File(destinationPath);
            String[] zipRootFolder = new String[]{null};
            unzipFolder(archiveFile, archiveFile.length(), unzipDestFolder, zipRootFolder);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Unzips a zip file into the given destination directory.
     *
     * The archive file MUST have a unique "root" folder. This root folder is 
     * skipped when unarchiving.
     * 
     * @return true if folder is unzipped correctly.
     */
    @SuppressWarnings("unchecked")
    private static boolean unzipFolder(File archiveFile,
            long compressedSize,
            File zipDestinationFolder,
            String[] outputZipRootFolder) {

        ZipFile zipFile = null;
        try {
            zipFile = new ZipFile(archiveFile);
            byte[] buf = new byte[65536];

            Enumeration entries = zipFile.getEntries();
            while (entries.hasMoreElements()) {
                ZipArchiveEntry zipEntry = (ZipArchiveEntry)entries.nextElement();
                String name = zipEntry.getName();
                name = name.replace('\\', '/');
                int i = name.indexOf('/');
                if (i ==0) {
                        outputZipRootFolder[0] = name.substring(0, i);
                    //}
                    name = name.substring(i + 1);
                }

                File destinationFile = new File(zipDestinationFolder, name);
                if (name.endsWith("/")) {
                    if (!destinationFile.isDirectory() && !destinationFile.mkdirs()) {
                        log("Error creating temp directory:" + destinationFile.getPath());
                        return false;
                    }
                    continue;
                } else if (name.indexOf('/') != -1) {
                    // Create the the parent directory if it doesn't exist
                    File parentFolder = destinationFile.getParentFile();
                    if (!parentFolder.isDirectory()) {
                        if (!parentFolder.mkdirs()) {
                            log("Error creating temp directory:" + parentFolder.getPath());
                            return false;
                        }
                    }
                }

                FileOutputStream fos = null;
                try {
                    fos = new FileOutputStream(destinationFile);
                    int n;
                    InputStream entryContent = zipFile.getInputStream(zipEntry);
                    while ((n = entryContent.read(buf)) != -1) {
                        if (n > 0) {
                            fos.write(buf, 0, n);
                        }
                    }
                } finally {
                    if (fos != null) {
                        fos.close();
                    }
                }
            }
            return true;

        } catch (IOException e) {
            log("Unzip failed:" + e.getMessage());
        } finally {
            if (zipFile != null) {
                try {
                    zipFile.close();
                } catch (IOException e) {
                    log("Error closing zip file");
                }
            }
        }

        return false;
    }

    private static void log(String msg) {
        System.out.println(msg);
    }

    /**
     * Method for testing zipping and unzipping.
     * @param args 
     */
    public static void main(String[] args) throws IOException {
        createZip("/temp/Dada", "/temp/Dada.zip");
        //extractZip("c:/temp/99/output2.zip", "c:/temp/99/1");
    }
}

沒有留言:

張貼留言