1. 程式人生 > 其它 >檔案壓縮與解壓

檔案壓縮與解壓

JAVA壓縮與解壓

需要的jar包

<dependency>
	<groupId>com.github.axet</groupId>
	<artifactId>java-unrar</artifactId>
	<version>1.7.0-3</version>
</dependency>
package com.util.base;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.util.Calendar;
import java.util.Enumeration;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
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;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;

import de.innosystec.unrar.Archive;
import de.innosystec.unrar.NativeStorage;
import de.innosystec.unrar.exception.RarException;
import de.innosystec.unrar.rarfile.FileHeader;

/**
 * 打包與解壓操作類
 * @author zhanglang
 * 2018-09-26
 */
public class ZipUtil {
	/**  
     * 遞迴壓縮資料夾  
     * @param srcRootDir 壓縮資料夾根目錄的子路徑  
     * @param file 當前遞迴壓縮的檔案或目錄物件  
     * @param zos 壓縮檔案儲存物件  
     * @throws Exception  
     */    
    private static void zip(String srcRootDir, File file, ZipOutputStream zos) throws Exception {    
        if (file == null){    
            return;    
        }                   
        //如果是檔案,則直接壓縮該檔案    
        if (file.isFile()){               
            int count, bufferLen = 2048;    
            byte data[] = new byte[bufferLen];    
                
            //獲取檔案相對於壓縮資料夾根目錄的子路徑    
            String subPath = file.getAbsolutePath();    
            int index = subPath.indexOf(srcRootDir);    
            if (index != -1){    
                subPath = subPath.substring(srcRootDir.length() + File.separator.length());    
            }    
            ZipEntry entry = new ZipEntry(subPath);    
            zos.putNextEntry(entry);    
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));    
            while ((count = bis.read(data, 0, bufferLen)) != -1){    
                zos.write(data, 0, count);    
            }    
            bis.close();    
            zos.closeEntry();    
        } else { 
        	//如果是目錄,則壓縮整個目錄    
            //壓縮目錄中的檔案或子目錄    
            File[] childFileList = file.listFiles();    
            if(childFileList != null) {
            	for (int n=0; n<childFileList.length; n++){    
                    childFileList[n].getAbsolutePath().indexOf(file.getAbsolutePath());    
                    zip(srcRootDir, childFileList[n], zos);    
                } 
            }
        }    
    }    
    
    /**  
     * 對檔案或檔案目錄進行壓縮  
     * @param srcPath 要壓縮的原始檔路徑。如果壓縮一個檔案,則為該檔案的全路徑;如果壓縮一個目錄,則為該目錄的頂層目錄路徑  
     * @param zipPath 壓縮檔案儲存的路徑。注意:zipPath不能是srcPath路徑下的子資料夾  
     * @param zipFileName 壓縮檔名  
     * @throws Exception  
     */    
    public static void zip(String srcPath, String zipPath, String zipFileName) throws Exception {    
        if (StringUtils.isEmpty(srcPath) 
        		|| StringUtils.isEmpty(zipPath) 
        		|| StringUtils.isEmpty(zipFileName)){    
            throw new TzException("Parameter null error.");    
        }    
        CheckedOutputStream cos = null;    
        ZipOutputStream zos = null;                         
        try{    
            File srcFile = new File(srcPath);    
                
            //判斷壓縮檔案儲存的路徑是否為原始檔路徑的子資料夾,如果是,則丟擲異常(防止無限遞迴壓縮的發生)    
            if (srcFile.isDirectory() && zipPath.indexOf(srcPath)!=-1){    
                throw new TzException("zipPath must not be the child directory of srcPath.");    
            }    
                
            //判斷壓縮檔案儲存的路徑是否存在,如果不存在,則建立目錄    
            File zipDir = new File(zipPath);    
            if (!zipDir.exists() || !zipDir.isDirectory()){    
                zipDir.mkdirs();    
            }    
                
            //建立壓縮檔案儲存的檔案物件    
            String zipFilePath = zipPath + (zipPath.endsWith(File.separator) ? "" : File.separator) + zipFileName;    
            File zipFile = new File(zipFilePath);               
            if (zipFile.exists()){    
                //檢測檔案是否允許刪除,如果不允許刪除,將會丟擲SecurityException
//                SecurityManager securityManager = new SecurityManager();    
//                securityManager.checkDelete(zipFilePath);
                //刪除已存在的目標檔案
                zipFile.delete();                   
            }    
                
            cos = new CheckedOutputStream(new FileOutputStream(zipFile), new CRC32());    
            zos = new ZipOutputStream(cos);    
                
            //如果只是壓縮一個檔案,則需要擷取該檔案的父目錄    
            String srcRootDir = srcPath;    
            if (srcFile.isFile()){    
                int index = srcPath.lastIndexOf(File.separator);    
                if (index != -1){    
                    srcRootDir = srcPath.substring(0, index);    
                }    
            }    
            //呼叫遞迴壓縮方法進行目錄或檔案壓縮    
            zip(srcRootDir, srcFile, zos);    
            zos.flush();    
        } catch (Exception e){    
            throw e;    
        } finally {               
            try{    
                if (zos != null){    
                    zos.close();    
                }                   
            }catch (Exception e){    
                e.printStackTrace();    
            }               
        }    
    }    

    /**  
     * 解壓縮zip包  
     * @param zipFilePath zip檔案的全路徑  
     * @param unzipFilePath 解壓後的檔案儲存的路徑  
     */
    @SuppressWarnings("unchecked")
	public static void unZip(String zipFilePath, String unzipFilePath) 
    		throws TzException {
    	if (StringUtils.isEmpty(zipFilePath) 
        		|| StringUtils.isEmpty(unzipFilePath)){    
            throw new TzException("引數錯誤");              
        }
        
        File zipFile = new File(zipFilePath);    
        if (!zipFile.exists()) {
            throw new TzException(zipFile.getPath() + "所指檔案不存在");
        }
        
        //建立解壓縮檔案儲存的路徑    
        File unzipFileDir = new File(unzipFilePath);    
        if (!unzipFileDir.exists() || !unzipFileDir.isDirectory()){    
            unzipFileDir.mkdirs();    
        }    
        
        if (zipFilePath.toLowerCase().endsWith(".rar")) {
        	unRar(zipFilePath, unzipFilePath);
    	}else {
    		if (!zipFilePath.toLowerCase().endsWith(".zip")) {
	            throw new TzException("檔案不是zip壓縮檔案");
	        }
	        //開始解壓
	        int count = 0, bufferSize = 2048;    
	        byte[] buffer = new byte[bufferSize];
	        ZipFile zip = null;
	        try {
		        zip = new ZipFile(zipFile, Charset.forName("GBK"));
		        Enumeration<ZipEntry> entries = (Enumeration<ZipEntry>)zip.entries();    
		        //迴圈對壓縮包裡的每一個檔案進行解壓         
		        while(entries.hasMoreElements()){    
		        	ZipEntry entry = entries.nextElement();
		        	
		        	if (entry.isDirectory()) {
		                String dirPath = unzipFilePath + File.separator + entry.getName();
		                File dir = new File(dirPath);
		                //如果資料夾路徑不存在,則建立資料夾    
		                if (!dir.exists()){    
		                	dir.mkdirs();
		                }
		            } else {
		            	//構建壓縮包中一個檔案解壓後儲存的檔案全路徑    
		                String entryFilePath = unzipFilePath + File.separator + entry.getName();    
		                
		                //建立解壓檔案    
		                File entryFile = new File(entryFilePath);    
		                if (entryFile.exists()){    
		                    //檢測檔案是否允許刪除,如果不允許刪除,將會丟擲SecurityException    
		                    //SecurityManager securityManager = new SecurityManager();    
		                    //securityManager.checkDelete(entryFilePath);
		                    //刪除已存在的目標檔案    
		                    entryFile.delete();
		                }    
		                    
		                //寫入檔案    
		                BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(entryFile));  
		                BufferedInputStream bis = new BufferedInputStream(zip.getInputStream(entry));    
		                while ((count = bis.read(buffer, 0, bufferSize)) != -1){    
		                    bos.write(buffer, 0, count);    
		                }  
		                //關閉
		                if(null != bis) bis.close();
		                if(null != bos){
		                	 bos.flush();    
		                     bos.close();
		                }
		            }
		        }
	        } catch (Exception e) {
	        	e.printStackTrace();
	            throw new TzException("解壓失敗", e);
	        } finally {
	            if(zip != null){
	                try {
	                	zip.close();
	                } catch (IOException e) {
	                    e.printStackTrace();
	                }
	            }
	        }
    	}
    }
    
    /**
     * 根據原始rar路徑,解壓到指定資料夾下. winrar5.0以上版本壓縮檔案解壓異常
     * @param srcRarPath 原始rar路徑
     * @param dstDirectoryPath 解壓到的資料夾
     * @throws TzException 
     */
    public static void unRar(String srcRarPath, String dstDirectoryPath) 
    		throws TzException {
    	if (StringUtils.isEmpty(srcRarPath) 
        		|| StringUtils.isEmpty(dstDirectoryPath)){    
            throw new TzException("引數錯誤");              
        }
    	
    	File zipFile = new File(srcRarPath);
        if (!zipFile.exists()) {
        	throw new TzException(zipFile.getPath() + "所指檔案不存在");
        }
    	
    	if (srcRarPath.toLowerCase().endsWith(".zip")) {
    		unZip(srcRarPath, dstDirectoryPath);
    	}else {
	        if (!srcRarPath.toLowerCase().endsWith(".rar")) {
	            throw new TzException("檔案不是rar壓縮檔案");
	        }
	        File dstDiretory = new File(dstDirectoryPath);
	        if (!dstDiretory.exists()) {// 目標目錄不存在時,建立該資料夾
	            dstDiretory.mkdirs();
	        }
	        Archive a = null;
	        FileOutputStream os = null;
	        try {
	        	NativeStorage nsFile = new NativeStorage(new File(srcRarPath));
	            a = new Archive(nsFile);
	            if (a != null) {
	                a.getMainHeader().print(); // 列印檔案資訊.
	                FileHeader fh = a.nextFileHeader();
	                while (fh != null) {
	                    String fileName=  fh.getFileNameW().trim();
	                    if(!existZH(fileName)){
	                        fileName = fh.getFileNameString().trim();
	                    }
	                    if (fh.isDirectory()) { // 資料夾
	                        File fol = new File(dstDirectoryPath + File.separator + fileName);
	                        fol.mkdirs();
	                    } else { // 檔案
	                        File out = new File(dstDirectoryPath + File.separator + fileName.trim());
	                        
	                        try {// 之所以這麼寫try,是因為萬一這裡面有了異常,不影響繼續解壓.
	                            if (!out.exists()) {
	                                if (!out.getParentFile().exists()) {// 相對路徑可能多級,可能需要建立父目錄.
	                                    out.getParentFile().mkdirs();
	                                }
	                                out.createNewFile();
	                            }
	                            os = new FileOutputStream(out);
	                            a.extractFile(fh, os);
	                            os.close();
	                            os = null;
	                        } catch (Exception ex) {
	                            ex.printStackTrace();
	                        }
	                    }
	                    fh = a.nextFileHeader();
	                }
	                a.close();
	                a = null;
	            }
	        }catch(RarException e) {
	        	e.printStackTrace();
	        	throw new TzException("程式不支援該壓縮格式,請將檔案壓縮成rar4或zip格式", e);
	        }catch(Exception e){    
	        	e.printStackTrace();
	        	throw new TzException("解壓失敗", e);   
	        }finally{
	            if(os!=null){    
	                try{
	                	os.close();
	                	os=null;
	                }catch(Exception e){
	                	e.printStackTrace();
	                }    
	            }    
	            if(a!=null){   
	                try{
	                	a.close();
	                	a=null;
	                }catch(Exception e){
	                	e.printStackTrace();
	                }    
	            }    
	        }  
    	}
    }
    
    /**
     * 刪除單個檔案
     * @param fileName 要刪除的檔案的檔名
     * @return 單個檔案刪除成功返回true,否則返回false
     */
    public static boolean deleteFile(String fileName) {
        File file = new File(fileName);
        // 如果檔案路徑所對應的檔案存在,並且是一個檔案,則直接刪除
        if (file.exists() && file.isFile()) {
            if (file.delete()) {
                System.out.println("刪除單個檔案" + fileName + "成功!");
                return true;
            } else {
                System.out.println("刪除單個檔案" + fileName + "失敗!");
                return false;
            }
        } else {
            System.out.println("刪除單個檔案失敗:" + fileName + "不存在!");
            return false;
        }
    }

    
    /**
     * 刪除目錄及目錄下的檔案
     * @param dir 要刪除的目錄的檔案路徑
     * @return 目錄刪除成功返回true,否則返回false
     */
    public static boolean deleteDirectory(String dir) {
        // 如果dir不以檔案分隔符結尾,自動新增檔案分隔符
        if (!dir.endsWith(File.separator))
            dir = dir + File.separator;
        File dirFile = new File(dir);
        // 如果dir對應的檔案不存在,或者不是一個目錄,則退出
        if ((!dirFile.exists()) || (!dirFile.isDirectory())) {
            System.out.println("刪除目錄失敗:" + dir + "不存在!");
            return false;
        }
        boolean flag = true;
        // 刪除資料夾中的所有檔案包括子目錄
        File[] files = dirFile.listFiles();
        for (int i = 0; i < files.length; i++) {
            // 刪除子檔案
            if (files[i].isFile()) {
                flag = ZipUtil.deleteFile(files[i].getAbsolutePath());
                if (!flag) break;
            }
            // 刪除子目錄
            else if (files[i].isDirectory()) {
                flag = ZipUtil.deleteDirectory(files[i].getAbsolutePath());
                if (!flag) break;
            }
        }
        if (!flag) {
            System.out.println("刪除目錄失敗!");
            return false;
        }
        // 刪除當前目錄
        if (dirFile.delete()) {
            System.out.println("刪除目錄" + dir + "成功!");
            return true;
        } else {
            return false;
        }
    }

    //判斷是否包含中文
    private static boolean existZH(String str) {
        String regEx = "[\\u4e00-\\u9fa5]";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(str);
        while (m.find()) {
            return true;
        }
        return false;
    }
    
    //生成隨機檔名,與檔案上傳命名一致
    public static String getNowTime() {
		Calendar cal = Calendar.getInstance();
		int year = cal.get(1);
		int month = cal.get(2) + 1;
		int day = cal.get(5);
		int hour = cal.get(10);
		int minute = cal.get(12);
		int second = cal.get(13);
		int mi = cal.get(14);
		long num = cal.getTimeInMillis();
		int rand = (int) (Math.random() * 899999 + 100000);
		return (new StringBuilder()).append(year).append(month).append(day).append(hour).append(minute).append(second)
				.append(mi).append(num).append("_").append(rand).toString();
	}

    
    /* sFile:原檔案地址,tFile目標檔案地址 */
	public static void copyFile(String sFile, String tFile) {
		// System.out.println("原檔案地址"+sFile+"目標"+tFile);
		FileInputStream fi = null;
		FileOutputStream fo = null;
		FileChannel in = null;
		FileChannel out = null;

		File s = new File(sFile);
		File t = new File(tFile);
		if (s.exists() && s.isFile()) {
			// System.out.println("是檔案");
			try {
				fi = new FileInputStream(s);
				fo = new FileOutputStream(t);
				in = fi.getChannel();// 得到對應的檔案通道
				out = fo.getChannel();// 得到對應的檔案通道
				in.transferTo(0, in.size(), out);// 連線兩個通道,並且從in通道讀取,然後寫入out通道
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				try {
					fi.close();
					in.close();
					fo.close();
					out.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	public static void copyFile2(String sFile, String tFile) {
		File srcFile = new File(sFile);
		if(srcFile.exists()){
			File destFile = new File(tFile);
			try {
				FileUtils.copyFile(srcFile, destFile);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}