1. 程式人生 > >Zip壓縮和解壓縮工具類

Zip壓縮和解壓縮工具類

依賴第三方jar包:ant-1.7.1.jar

/**  
* @Title: ZipUtils.java  
* @Package com.sz.mt.test.zip  
* @Description: TODO(ZIP壓縮及解壓工具類)  
* @author: LokChow 
* @version V1.0  
*/  
package com.sz.mt.test.zip;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.Expand;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipOutputStream;

/**  
 * @ClassName: ZipUtils  
 * @Description: TODO(ZIP實現檔案的壓縮和解壓縮工具類)  
 * @author LokChow  
 * @date 2018-11-27  
 *  
 */
public class ZipUtils {
	
	private static final int  BUFFER_SIZE = 4 * 1024;
	
	/**
	* @Title: unzip  
	* @Description: TODO(解壓zip格式壓縮包)  
	* @param @param sourceZip 待解壓檔案路徑
	* @param @param destDir 解壓後的路徑
	* @param @return    引數  
	* @return boolean    返回型別  
	* @throws
	 */
	private static boolean unzip(String sourceZip, String destDir) {
		try {
			Project project = new Project();
			Expand expand  = new Expand();
			expand.setProject(project);
			expand.setSrc(new File(sourceZip));
			expand.setOverwrite(false);
			expand.setDest(new File(destDir));
			/*
			* ant下的zip工具預設壓縮編碼為UTF-8編碼,
			* 而winRAR軟體壓縮是用的windows預設的GBK或者GB2312編碼
			* 所以解壓縮時要制定編碼格式
			*/
			expand.setEncoding("gbk");
			expand.execute();
		} catch (BuildException e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}
	
	/**
	 * 遞迴壓縮方法
	 * @param sourceFile 原始檔
	 * @param zos        zip輸出流
	 * @param name       壓縮後的名稱
	 * @param KeepDirStructure  是否保留原來的目錄結構,true:保留目錄結構; 
	 *                          false:所有檔案跑到壓縮包根目錄下(注意:不保留目錄結構可能會出現同名檔案,會壓縮失敗)
	 * @throws Exception
	 */
	private static void compress(File sourceFile, ZipOutputStream zos, String name,
			            boolean KeepDirStructure) throws Exception{
		if (!sourceFile.exists()) return;
		FileInputStream fis = null;
		byte buf[] = new byte[BUFFER_SIZE];
		if (sourceFile.isFile()) {
			// 向zip輸出流中新增一個zip實體,構造器中name為zip實體的檔案的名字
			zos.putNextEntry(new ZipEntry(name));
			// copy檔案到zip輸出流中
			int len;
			fis = new FileInputStream(sourceFile);
			while((len = fis.read(buf)) != -1){
				zos.write(buf,0,len);//copy並寫到壓縮檔案中
			}
			// 解壓完畢
			zos.closeEntry();
			fis.close();
		}else{
			File Listfiles[] = sourceFile.listFiles();
			//沒有檔案
			if (Listfiles == null || Listfiles.length == 0) {
				// 需要保留原來的檔案結構時,需要對空資料夾進行處理
				if (KeepDirStructure) {
					// 空資料夾的處理
					zos.putNextEntry(new ZipEntry(name+"/"));
					// 沒有檔案,不需要檔案的copy
					zos.closeEntry();
				}
			}else{
				for (File file : Listfiles) {
					// 判斷是否需要保留原來的檔案結構
					if (KeepDirStructure) {
						// 注意:file.getName()前面需要帶上父資料夾的名字加一斜槓,
					    // 不然最後壓縮包中就不能保留原來的檔案結構,即:所有檔案都跑到壓縮包根目錄下了
						compress(file, zos, name+"/"+file.getName(), KeepDirStructure);
					}else{
						compress(file, zos, file.getName(), KeepDirStructure);
					}
				}
			}
		}
	}
	
	/**
	* @Title: toZip1  
	* @Description: TODO(壓縮成ZIP)  
	* @param srcDir 壓縮資料夾路徑 
	* @param out 壓縮檔案輸出流
	* @param KeepDirStructure    是否保留原來的目錄結構,true:保留目錄結構; 
	* 		false:所有檔案跑到壓縮包根目錄下(注意:不保留目錄結構可能會出現同名檔案,會壓縮失敗)  
	* @return void    返回型別
	* @throws RuntimeException 壓縮失敗會丟擲執行時異常
	 */
	public static void toZip1(String srcDir, OutputStream out, boolean KeepDirStructure) throws RuntimeException{
		long start = System.currentTimeMillis();
		ZipOutputStream zos = null;
		try {
			zos = new ZipOutputStream(out);
			//設定檔名編碼方式(將系統的ZIP編碼格式設定為系統檔名編碼方式,否則中文名稱檔名亂碼及解壓時報異常.)
			zos.setEncoding(System.getProperty("sun.jnu.encoding"));
			File sourceFile = new File(srcDir);
			compress(sourceFile, zos, sourceFile.getName(), KeepDirStructure);
			long end = System.currentTimeMillis();
			System.out.println("壓縮完畢,共耗時:"+(end-start)/1000+"秒");
		} catch (Exception e) {
			throw new RuntimeException("zip error from ZipUtils",e);
		}finally{
			if (null != zos) {
				try {
					zos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	/**
	* @Title: toZip  
	* @Description: TODO(壓縮成ZIP 方法2)  
	* @param srcFiles  需要壓縮的檔案列表
	* @param out  壓縮檔案輸出流
	* @throws RuntimeException    壓縮失敗會丟擲執行時異常  
	* @return void    返回型別
	 */
	public static void toZip(List<File> srcFiles , OutputStream out)throws RuntimeException {
		long start = System.currentTimeMillis();
		ZipOutputStream zos = null;
		FileInputStream fis = null;
		try {
			zos = new ZipOutputStream(out);
			for (File srcFile : srcFiles) {
				byte buf[] = new byte[BUFFER_SIZE];
				// 向zip輸出流中新增一個zip實體,構造器中name為zip實體的檔案的名字
				zos.putNextEntry(new ZipEntry(srcFile.getName()));
				int len;
				fis = new FileInputStream(srcFile);
				while((len = fis.read(buf)) != -1){
					zos.write(buf, 0, len);
				}
				zos.closeEntry();
				fis.close();
			}
			long end = System.currentTimeMillis();
			System.out.println("解壓完畢,共耗時:"+(end-start)/1000+"秒");
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}catch (Exception e){
			 throw new RuntimeException("zip error from ZipUtils",e);
		}finally{
			if (null != zos) {
				try {
					zos.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
	
	
	
	public static void main(String[] args) {
		//測試toZip1壓縮
		/*String srcPath = "F:\\我的工具\\你好.txt";
		try {
			FileOutputStream fos1 = new FileOutputStream(new File("f:\\我的工具\\test01.zip"));
			toZip1(srcPath, fos1, true);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		*/
		//測試解壓
		unzip("F:\\我的工具\\test01.zip", "F:\\");
	}

}