1. 程式人生 > >Java IO操作--壓縮包zip實現工具類

Java IO操作--壓縮包zip實現工具類

壓縮檔案大致可以分為三種:ZIP、JAR、GZ。

壓縮流

在日常的使用中經常會使用到像WinRAR或WinZIP這樣的壓縮檔案,通過這些軟體可以把一個很大的檔案進行壓縮以方便傳輸。

在JAVA中 為了減少傳輸時的資料量也提供了專門的壓縮流,可以將檔案或資料夾壓縮成ZIP、JAR、GZIP等檔案的格式。  

壓縮流的實現:正常情況下在IO操作中,所有的類庫都是在io包中。

在JAVA IO中,不僅可以實現ZIP壓縮格式的輸入、輸出,也可以實現JAR及GZIP檔案格式的壓縮:

JAR壓縮的支援類儲存在java.util.jar包中,常用的類有如下幾個:  JAR壓縮輸出流:JarOutputStream  JAR壓縮輸入流:JarInputStream  JAR檔案:JARFile  JAR實體:JAREntry

GZIP是用於UNIX系統的檔案壓縮,在Linux中經常會使用到*.gz的檔案,就是GZIP格式,GZIP壓縮的支援類儲存在java.util.zip包中,常用的類有如下幾個: GZIP壓縮輸出流:GZIPOutputStream GZIP壓縮輸入流:GZIPInputStream  

ZIP是一種較為常見的壓縮形式,在Java中要想實現ZIP的壓縮需要匯入java.util.zip包,可以使用此包中的ZipFile、ZipOutputStream、ZipInputStream、ZipEntry幾個類完成。

1)ZipEntry:API文件   在每一個壓縮檔案中都會存在多個子檔案,那麼這每一個的子檔案在JAVA中就使用ZipEntry表示。   在例項化ZipEntry的時候,要設定名稱,此名稱實際上就是壓縮檔案中的每一個元素中的名稱

建立具有指定名稱的新zip條目。

建立一個新的zip條目,其中包含從指定的zip條目中獲取的欄位。

boolean

如果這是目錄條目,則返回true。

2)ZipFile:API文件

是一個專門表示壓縮檔案的類,在JAVA中,每一個壓縮檔案都可以使用ZipFile表示,還可以使用ZipFile根據壓縮後的檔名稱找到每一個壓縮檔案中的ZipEntry並將其進行解壓縮操作。ZipFile在例項化的時候必須接收File類的例項,此File類的例項是指向一個壓縮的*.zip檔案。

3)ZipInputStream:

可以不用輸入實體名稱,就可以得到每一個ZipEntry物件

void

關閉當前ZIP條目並定位流以讀取下一個條目。

4)ZipOutputStream:API文件 如果要想完成一個檔案或資料夾的壓縮,要使用ZipOutputStream類完成,ZipOutputStream是OutputStream的子類。

此類的功能就是完成ZIP格式輸出的

void close()

關閉ZIP輸出流以及要過濾的流。

void

關閉當前ZIP條目並定位流以寫入下一個條目。

void

開始編寫新的ZIP檔案條目並將流定位到條目資料的開頭。

總結: 1、壓縮檔案中的每一個壓縮實體都使用ZipEntry儲存,一個壓縮檔案中可能包含一個或多個ZipEntry物件。 2、在JAVA中可以進行zip、jar、gz三種格式的壓縮支援,操作流程基本上是一致的。 3、ZipOutputStream可以進行壓縮的輸出,但是輸出的位置不一定是檔案。 4、ZipFile表示每一個壓縮檔案,可以得到每一個壓縮實體的輸入流。  

1、單檔案壓縮:

	public static void main(String[] args) throws Exception {
		File file = new File("E:\\java\\file01\\使用者Table基本資訊.xlsx");
		String zipFilePath = "E:\\java\\file04";
		ZipFileUtil.zipOneFile(zipFilePath, file);
	}

2、 遞迴實現巢狀檔案或不巢狀資料夾的壓縮 

對一個資料夾進行壓縮,例如,現在在某盤存在一個liuxun的資料夾。從使用各種壓縮軟體的經驗來看,如果現在要進行壓縮的話,則在壓縮之後的檔案中應該存在一個liuxun的資料夾。在資料夾中應該存放著各個壓縮檔案。所以在實現的時候就應該列出資料夾中的全部內容,並把每一個內容設定成ZipEntry的物件,儲存到壓縮檔案之中。    

	public static void main(String[] args) throws Exception {
		File fileDir = new File("E:\\java\\file01");
		String zipFilePath = "E:\\java\\file04";
		ZipFileUtil.zipFileDir(zipFilePath, fileDir, true);
	}

3、解壓縮檔案到指定目錄下

如果指定目錄或檔案不存在,則應該進行建立操作。

	public static void main(String[] args) throws Exception {
		File zipfile = new File("E:\\java\\file04\\file01.zip"); // 定義壓縮檔名稱
		String descDir = "E:\\java\\file04";
		ZipFileUtil.unZipFile(zipfile, descDir);
	}

4、自定義工具類:FileToZipUtil

public class ZipFileUtil {

	/**
	 * 壓縮一個檔案
	 * 
	 * @param zipFilePath 宣告壓縮檔案路徑
	 * @param file        要壓縮的檔案
	 * @throws Exception
	 */
	public static void zipOneFile(String zipFilePath, File file) throws Exception {
		// 檢查目錄是否存在,不存在時建立
		File dir = new File(zipFilePath);
		if (!dir.isDirectory()) {
			dir.mkdirs();
		}

		File zipFile = new File(dir, file.getName().substring(0, file.getName().indexOf(".")) + ".zip"); // 定義壓縮檔名稱
		ZipOutputStream zipOut = null; // 宣告壓縮流物件
		try {
			InputStream input = new FileInputStream(file);
			zipOut = new ZipOutputStream(new FileOutputStream(zipFile));
			zipOut.putNextEntry(new ZipEntry(file.getName())); // 設定ZipEntry物件
			zipOut.setComment("UTF-8"); // 設定註釋
			byte[] buffer = new byte[1024];
			int len = -1;
			while ((len = input.read(buffer)) != -1) {
				zipOut.write(buffer, 0, len);
			}
			input.close();
		} finally {
			if (zipOut != null) {
				zipOut.flush();
				zipOut.closeEntry();
				zipOut.close();
			}
		}
	}

	/**
	 * 壓縮一個檔案返回輸出流
	 * 
	 * @param zipFilePath
	 * @param file
	 * @return OutputStream
	 * @throws Exception
	 */
	public static OutputStream zipOneFileToOut(String zipFilePath, File file) throws Exception {
		// 檢查目錄是否存在,不存在時建立
		File dir = new File(zipFilePath);
		if (!dir.isDirectory()) {
			dir.mkdirs();
		}

		File zipFile = new File(dir, file.getName().substring(0, file.getName().indexOf(".")) + ".zip"); // 定義壓縮檔名稱
		ZipOutputStream zipOut = null; // 宣告壓縮流物件
		try {
			InputStream input = new FileInputStream(file);
			zipOut = new ZipOutputStream(new FileOutputStream(zipFile));
			zipOut.putNextEntry(new ZipEntry(file.getName())); // 設定ZipEntry物件
			zipOut.setComment("UTF-8"); // 設定註釋
			byte[] buffer = new byte[10240];
			int len = -1;
			while ((len = input.read(buffer)) != -1) {
				zipOut.write(buffer, 0, len);
			}
			input.close();
		} finally {
			if (zipOut != null) {
				zipOut.flush();
				zipOut.closeEntry();
				zipOut.close();
			}
		}
		return zipOut;
	}

	/**
	 * 壓縮一個巢狀檔案或不巢狀資料夾
	 * 
	 * @param zipFilePath 宣告壓縮檔案路徑
	 * @param fileDir     要壓縮的資料夾
	 * @param dirFlag     要壓縮的資料夾是否巢狀資料夾,true巢狀;false沒有
	 * @throws Exception
	 */
	public static void zipFileDir(String zipFilePath, File fileDir, boolean dirFlag) throws Exception {
		// 檢查目錄是否存在,不存在時建立
		File dir = new File(zipFilePath);
		if (!dir.isDirectory()) {
			dir.mkdirs();
		}

		ZipOutputStream zipOut = null; // 宣告壓縮流物件
		InputStream input = null;
		try {
			File zipFile = new File(dir, fileDir.getName() + ".zip"); // 定義壓縮檔名稱
			zipOut = new ZipOutputStream(new FileOutputStream(zipFile));
			zipOut.setComment("UTF-8"); // 設定註釋

			if (fileDir.isDirectory()) { // 判斷是否是資料夾
				File[] files = fileDir.listFiles();
				for (File fileSec : files) {
					if (dirFlag) {
						recursionZip(zipOut, fileSec, fileDir.getName() + File.separator);
					} else {
						recursionZip(zipOut, fileSec, fileDir.getName() + File.separator);
					}
				}
			}
		} finally {
			if (zipOut != null) {
				zipOut.flush();
				zipOut.closeEntry();
				zipOut.close();
			}
		}
	}

	/**
	 * 遞迴實現巢狀檔案或不巢狀資料夾的壓縮 void
	 * 
	 * @param zipOut
	 * @param file
	 * @param baseDir
	 * @throws Exception
	 */
	private static void recursionZip(ZipOutputStream zipOut, File file, String baseDir) throws Exception {
		if (file.isDirectory()) {
			File[] files = file.listFiles();
			for (File fileSec : files) {
				recursionZip(zipOut, fileSec, baseDir + file.getName() + File.separator); // 遞迴
			}
		} else {
			InputStream input = new FileInputStream(file);
			zipOut.putNextEntry(new ZipEntry(baseDir + file.getName())); // 設定ZipEntry物件: 解壓檔案會在原檔案目錄下
			zipOut.setComment("UTF-8"); // 設定註釋
			byte[] buffer = new byte[1024];
			int len = -1;
			while ((len = input.read(buffer)) != -1) {
				zipOut.write(buffer, 0, len);
			}
			input.close();
		}
	}

	/**
	 * 功能:解壓縮
	 * 
	 * @param file:需要解壓縮的檔案
	 * @param descDir:解壓後的目標目錄
	 * @throws IOException 
	 * @throws ZipException 
	 */
	public static void unZipFile(File file, String descDir) throws Exception {
		ZipFile zipFile = new ZipFile(file);	// 例項化ZipFile物件
		ZipInputStream zipInput = new ZipInputStream(new FileInputStream(file)); // 例項化壓縮輸入流
		ZipEntry entry = null;	
		
		OutputStream out = null;	// 定義輸出流,用於輸出每一個實體內容
		InputStream input = null;	// 定義輸入流,讀取每一個ZipEntry
		
		while((entry = zipInput.getNextEntry()) != null){	// 得到每一個壓縮實體物件
			//System.out.println("解壓縮 " + entry.getName() + "檔案。");
			File outFile = new File(descDir + File.separator + entry.getName());	// 定義要輸出的路徑檔案
			if(!outFile.getParentFile().exists()){	// 如果輸出資料夾不存在
				outFile.getParentFile().mkdir() ;	// 建立資料夾
			}
			if(!outFile.exists()){			// 判斷輸出檔案是否存在
				outFile.createNewFile() ;	// 建立檔案
			}
			
			try {
				input = zipFile.getInputStream(entry); // 得到每一個壓縮實體物件的輸入流
				out = new FileOutputStream(outFile); // 例項化檔案輸出流
				byte[] buffer = new byte[1024];
				int len = -1;
				while ((len = input.read(buffer)) != -1) {
					out.write(buffer, 0, len);
				} 
			} finally {
				input.close() ;	
				out.close() ;	
			}
		}
	}

}

參考文章:

中文亂碼的問題都是基於JDK6,但是在JDK7中已經解決了,只要把JDK版本升到7就可以。