Java生成Zip格式文件之歸檔、打包、壓縮、解壓

問題描述:zip 文件打包與解壓是作爲程序猿的我們經常會碰到的問題,但是這麼常見的功能,還自己一行一行的去碼代碼,實在是有點浪費時間。上網一搜,滿屏幕的 zip 壓縮解決工具類,複製下來一運行,各種BUG,煩~~~不過,現在好了,你煩的事情我已經煩過了,所以特意把我煩之後的結果貼出來,減輕各位同學的煩惱。好了,話不多說,上代碼。

package com.utility.zip;

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.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

/**
 * Zip 文件工具類
 * 
 * @ClassName: ZipUtil
 * @author Supreme_Sir
 * @date 2020年6月30日 上午10:47:28
 */
public class ZipUtil {
    /**
     * 緩衝區
     */
    private static final int BUFFER = 2048;

    /**
     * 壓縮的文件後綴名
     */
    private static final String SUFFIX = ".zip";

    /**
     * 解壓字符集
     */
    private static final String ENCODE = "UTF-8";

    /**
     * 得到源文件路徑的所有文件
     * 
     * @Title: getAllFile 
     * @param dirFile 壓縮源文件路徑 
     * @return List<File> 
     * @throws
     */
    public static List<File> getAllFile(File dirFile) {
        List<File> fileList = new ArrayList<File>();
        // 判斷傳入的參數是否爲文件夾
        if (dirFile.isDirectory()) {
            File[] files = dirFile.listFiles();
            // 遍歷目標路徑下的所有文件
            for (File file : files) {
                // 判斷文件類型,如果是文件則直接添加至結果集合中,如果爲文件夾,則遞歸添加
                if (file.isFile()) {
                    fileList.add(file);
                } else {
                    if (file.listFiles().length != 0) {
                        fileList.addAll(getAllFile(file));
                    } else {
                        fileList.add(file);
                    }
                }
            }
        } else {
            fileList.add(dirFile);
        }
        return fileList;
    }

    /**
     * 獲取相對路徑
     * 
     * @Title: getRelativePath 
     * @param dirPath 源文件路徑 
     * @param file 準備壓縮的單個文件 
     * @return String 
     * @throws
     */
    public static String getRelativePath(String dirPath, File file) {
        // 創建源文件所在目錄,用以控制路徑深度
        File dirFile = new File(dirPath);
        // 獲取當前文件的文件名
        String relativePath = file.getName();
        while (true) {
            // 獲取當前文件所在的目錄
            file = file.getParentFile();
            if (file == null)
                break;
            // 判斷當前文件目錄是否爲源文件所在目錄
            if (file.equals(dirFile)) {
                break;
            } else {
                // 拼裝相對路徑
                relativePath = file.getName() + "/" + relativePath;
            }
        }
        return relativePath;
    }

    /**
     * 將壓縮後的文件保存至源文件所在磁盤的根目錄
     * 
     * @Title: compress2RootPath 
     * @param dirPath 壓縮源文件路徑 
     * @throws
     */
    public static void compress2RootPath(String dirPath) {
        int firstIndex = 0;
        int lastIndex = 0;
        // 判斷路徑分割符
        if (dirPath.contains("/")) {
            firstIndex = dirPath.indexOf("/");
            lastIndex = dirPath.lastIndexOf("/");
        } else {
            firstIndex = dirPath.indexOf("\\");
            lastIndex = dirPath.lastIndexOf("\\");
        }
        // 生成壓縮後文件的絕對路徑
        String zipFileName = dirPath.substring(0, firstIndex + 1) + dirPath.substring(lastIndex + 1);
        compress2CustomPath(dirPath, zipFileName);
    }

    /**
     * 將指定路徑的文件壓縮至指定位置
     * 
     * @Title: compress2CustomPath 
     * @param dirPath 壓縮源文件路徑 
     * @param zipFileName 壓縮目標文件路徑 
     * void 
     * @throws
     */
    public static void compress2CustomPath(String dirPath, String zipFileName) {
        zipFileName = zipFileName + SUFFIX;
        File dirFile = new File(dirPath);
        // 獲取目標路徑下所有的文件
        List<File> fileList = getAllFile(dirFile);
        byte[] buffer = new byte[BUFFER];
        ZipEntry zipEntry = null;
        // 每次讀取出來的長度
        int readLength = 0;
        try {
            // 對輸出文件做CRC32校驗
            CheckedOutputStream cos = new CheckedOutputStream(new FileOutputStream(zipFileName), 
            	new CRC32());
            ZipOutputStream zos = new ZipOutputStream(cos);
            for (File file : fileList) {
                // 若是文件,則壓縮文件
                if (file.isFile()) {
                    zipEntry = new ZipEntry(getRelativePath(dirPath, file));
                    zipEntry.setSize(file.length());
                    zipEntry.setTime(file.lastModified());
                    zos.putNextEntry(zipEntry);
                    InputStream is = new BufferedInputStream(new FileInputStream(file));
                    while ((readLength = is.read(buffer, 0, BUFFER)) != -1) {
                        zos.write(buffer, 0, readLength);
                    }
                    is.close();
                    // 若是空目錄,則寫入zip條目中
                } else {
                    zipEntry = new ZipEntry(getRelativePath(dirPath, file));
                    zos.putNextEntry(zipEntry);
                }
            }
            // 最後得關閉流,不然壓縮最後一個文件會出錯
            zos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 解壓Zip文件
     * 
     * @param path                    文件目錄
     * @param explorerIntoCurrentPath 是否解壓到當前目錄 
     *                  true:解壓到文件所在目錄 
     *                  false:解壓到壓縮包同名文件夾內
     */
    public static void decompress(String path, boolean explorerIntoCurrentPath) {
        int count = -1;
        File file = null;
        InputStream is = null;
        FileOutputStream fos = null;
        BufferedOutputStream bos = null;
        // 初始化文件保存路徑
        String savepath = path.split(":")[0] + ":" + File.separator;
        // 判斷是否解壓到文件所在目錄
        if (!explorerIntoCurrentPath) {
            // 重置文件保存路徑
            savepath = path.substring(0, path.lastIndexOf(".")) + File.separator;
            // 創建保存目錄
            new File(savepath).mkdir();
        }
        ZipFile zipFile = null;
        try {
            // 解決中文亂碼問題
            zipFile = new ZipFile(path, Charset.forName(ENCODE));
            // 獲取壓縮包內文件集合
            Enumeration<?> entries = zipFile.entries();
            while (entries.hasMoreElements()) {
                byte buf[] = new byte[BUFFER];
                ZipEntry entry = (ZipEntry) entries.nextElement();
                // 獲取當前文件
                String filename = entry.getName();
                // 是否需要創建文件夾標識
                boolean ismkdir = false;
                int fileSeparatorIndex = filename.lastIndexOf("/");
                // 檢查此文件是否需要創建文件夾
                if (fileSeparatorIndex != -1 && 
                	!new File(savepath + filename.substring(0, fileSeparatorIndex)).exists()) {
                    ismkdir = true;
                }
                filename = savepath + filename;
                file = new File(filename);
                // 如果需要創建文件夾,則先創建文件夾
                if (ismkdir) {
                    new File(filename.substring(0, filename.lastIndexOf("/"))).mkdirs();
                }
                // 創建文件
                file.createNewFile();
                is = zipFile.getInputStream(entry);
                fos = new FileOutputStream(file);
                bos = new BufferedOutputStream(fos, BUFFER);
                while ((count = is.read(buf)) > -1) {
                    bos.write(buf, 0, count);
                }
                bos.flush();
                bos.close();
                fos.close();
                is.close();
            }
            zipFile.close();
        } catch (IOException ioe) {
            ioe.printStackTrace();
        } finally {
            try {
                if (bos != null) {
                    bos.close();
                }
                if (fos != null) {
                    fos.close();
                }
                if (is != null) {
                    is.close();
                }
                if (zipFile != null) {
                    zipFile.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        compress2RootPath("F:\\頭像 - 副本.jpeg");
        decompress("F:\\ant.zip", false);
    }
}

上面的代碼,是博主從茫茫代碼中搜集後整理的結果,已完成基本BUG的修復和關鍵邏輯的註釋。

主要功能:

  1. 支持文件壓縮
  2. 支持文件夾壓縮
  3. 支持自定義文件解壓路徑
  4. 默認將文件解壓至所在磁盤根目錄

-------------------- 懂事後,開始不去爲了讀書而讀書,而是在書中讀自己,在書中發現自己,或檢查自己。 --------------------

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章