提示:
本文簡單介紹介紹了一下JDK中的zip接口,但JDK自帶的zip操作接口非常不完善,既不支持中文,也不支持密碼,所以可用性不高。
如果您有在Java語言環境中處理zip壓縮文件的需要,推薦采用zip4j這一開源項目,zip4j支持多種加密和壓縮算法,采用unicode編碼,所以也支持中文,其它方面也是非常優秀,可以說是功能強大。
詳見另一篇文章: http://www.linuxidc.com/Linux/2014-11/109061.htm
最近由於工作需要,對Java語言下的ZIP和RAR解壓和壓縮作了一些了解,現記錄一下,以備不時之需,如果能幫到各位朋友,自是大佳。
首先說說ZIP格式:
JDK本身就已經提供了操作ZIP文件的接口(在java.util.zip包下),這些接口使用起來很簡單,該包下主要涉及了
ZipEntry // 此類用於表示 ZIP 文件條目
ZipFile // 此類用於從 ZIP 文件讀取條目
ZipInputStream // 此類為讀取 ZIP 文件格式的文件實現輸入流
ZipOutputStream // 此類為以 ZIP 文件格式寫入文件實現輸出流
等幾個類,其它的類有些跟校驗有關,還有一些不明白了,基本使用中沒有用到。
其中ZipEntry代表ZIP文件中一條項目(包括目錄和文件),ZipFile則表示一個zip壓縮文件,ZipFile類中提供了獲取其代表文件中的所有Entry的方法,通過這些方法我們可以取得第一條ZipEntry,該對象中有我們需要的信息,可以通過讀寫流操作將其從壓縮文件中抽出,並寫到本地磁盤,完成操作也就表示完成了ZIP文件的解壓。
ZipInputStream 表示ZIP文件的輸入流,通過該類也可以完成解壓,其中也有獲取ZipEntry的方法,同ZipFile類似可以通過流的讀寫完成解壓。
ZipOutputStream 表示ZIP文件的輸出流,可以完成ZIP壓縮,也是通過其相關方法將新建ZipEntry(目錄或文件)添加進輸出流,然後同樣通過流的讀寫將本地磁盤文件寫進ZIP壓縮文件(如果是目錄則不需要流操作,僅需將ZipEntry添加進輸出流即可),最後輸出到磁盤。
在解壓過程中有一個問題需要注意,就是壓縮文件中含有目錄嵌套這種情況,其實ZipEntry中有一個方法isDirectory(),但我試了一下,不論何種情況該方法都反回false,不知道是不是自己有什麼 地方沒有做對,於是就想用一種比較笨的方式創建目錄:如果當前ZipEntry的name(可以能過getName()獲得)以File.separator結尾說明該Entry是個目錄,將其創建,如果不是則將其抽出。如果哪位有好的方式請賜教。
說多了也沒啥用,個人理解也不是很透徹,下面是一個比較簡單的示例,僅僅是幾個API的使用,不過仍然簡單地完成了壓縮和解壓縮,如果您在關注,希望能起到點拋磚引玉的作用。
JDK自帶的ZIP包解壓ZIP壓縮文件:
package com.ninemax.demo.zip;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
/**
* 壓縮指定的文件或目錄
* 解壓指定的壓縮文件(僅限ZIP格式).
* 采用JDK1.6,不依賴其它開源項目
* @author zyh
*/
public class ZipUtil {
/**
* 將指定文件或者指定目錄下的所有文件壓縮並生成指定路徑的壓縮文件.
* 如果壓縮文件的路徑或父路徑不存在, 將會自動創建.
* @param srcFile 將要進行壓縮的文件或目錄
* @param destfFile 最終生成的壓縮文件的路徑
* @throws IOException
*/
public static void zipFile(String srcFile,String destFile) throws IOException {
zipFile(new File(srcFile), new File(destFile));
}
/**
* 將指定文件或目錄下的所有文件壓縮並生成指定路徑的壓縮文件.
* 如果壓縮文件的路徑或父路徑不存在, 將會自動創建.
* @param srcFile 將要進行壓縮的文件或目錄
* @param destFile 最終生成的壓縮文件的路徑
* @throws IOException
*/
public static void zipFile(File srcFile,File destFile) throws IOException {
zipFile(srcFile, FileUtils.openOutputStream(destFile));
}
/**
* 將指定文件或目錄下的所有文件壓縮並將流寫入指定的輸出流中.
*
* @param srcFile 將要進行壓縮的目錄
* @param outputStream 用於接收壓縮產生的文件流的輸出流
*/
private static void zipFile(File srcFile,OutputStream outputStream) {
zipFile(srcFile, new ZipOutputStream(outputStream));
}
/**
* 將指定目錄下的所有文件壓縮並將流寫入指定的ZIP輸出流中.
*
* @param srcFile 將要進行壓縮的目錄
* @param zipOut 用於接收壓縮產生的文件流的ZIP輸出流
*/
private static void zipFile(File srcFile,ZipOutputStream zipOut) {
try {
doZipFile(srcFile,zipOut, "");
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(zipOut);
}
}
/**
* 壓縮文件或目錄到指定ZipOutputStream
* @param srcFile 指定文件或者目錄
* @param zipOut 指定ZipOutputStream輸出流
* @param ns 文件組織到ZIP文件時的路徑
* @throws IOException
*/
private static void doZipFile(File srcFile, ZipOutputStream zipOut,
String ns) throws IOException {
if (srcFile.isFile()) {
zipOut.putNextEntry(new ZipEntry(ns + srcFile.getName()));
InputStream is = FileUtils.openInputStream(srcFile);
try {
IOUtils.copy(is, zipOut);
} catch (Exception e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(is);
}
return;
}
for (File file : srcFile.listFiles()) {
String entryName = ns + file.getName();
if (file.isDirectory()) {
entryName += File.separator;
zipOut.putNextEntry(new ZipEntry(entryName));
}
doZipFile(file, zipOut, entryName);
}
}
/**
* 將指定的壓縮文件解壓到指定的目標目錄下.
* 如果指定的目標目錄不存在或其父路徑不存在, 將會自動創建.
*
* @param zipFile 將會解壓的壓縮文件
* @param destFile 解壓操作的目錄
*/
public static void unzipFile(String zipFile,String destFile) throws IOException {
unzipFile(new File(zipFile), new File(destFile));
}
/**
* 將指定的壓縮文件解壓到指定的目標目錄下.
* 如果指定的目標目錄不存在或其父路徑不存在, 將會自動創建.
*
* @param zipFile 將會解壓的壓縮文件
* @param destFile 解壓操作的目錄目錄
*/
public static void unzipFile(File zipFile,File destFile) throws IOException {
unzipFile(FileUtils.openInputStream(zipFile), destFile);
// doUnzipFile(new ZipFile(zipFile), destFile);
}
public static void doUnzipFile(ZipFile zipFile,File dest) throws IOException {
if (!dest.exists()) {
FileUtils.forceMkdir(dest);
}
Enumeration<ZipEntry> entries = (Enumeration<ZipEntry>) zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
File file = new File(dest, entry.getName());
if (entry.getName().endsWith(File.separator)) {
FileUtils.forceMkdir(file);
} else {
OutputStream out = FileUtils.openOutputStream(file);
InputStream in = zipFile.getInputStream(entry);
try {
IOUtils.copy(in, out);
} catch (Exception e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(out);
}
}
}
zipFile.close();
}
/**
* 將指定的輸入流解壓到指定的目標目錄下.
*
* @param is 將要解壓的輸入流
* @param destFile 解壓操作的目標目錄
* @throws IOException
*/
public static void unzipFile(InputStream is,File destFile) throws IOException {
try {
if (is instanceof ZipInputStream) {
doUnzipFile((ZipInputStream) is,destFile);
} else {
doUnzipFile(new ZipInputStream(is), destFile);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(is);
}
}
/**
*
* @param zipInput
* @param dest
* @throws IOException
*/
private static void doUnzipFile(ZipInputStream zipInput, File dest)
throws IOException {
if (!dest.exists()) {
FileUtils.forceMkdir(dest);
}
for (ZipEntry entry; (entry = zipInput.getNextEntry()) != null;) {
String entryName = entry.getName();
File file = new File(dest, entry.getName());
if (entryName.endsWith(File.separator)) {
FileUtils.forceMkdir(file);
} else {
OutputStream out = FileUtils.openOutputStream(file);
try {
IOUtils.copy(zipInput, out);
} catch (Exception e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(out);
}
}
zipInput.closeEntry();
}
}
// 測試
public static void main(String[] args) {
try {
// zipFile("M:\\ZIP\\test\\tempZIP", "M:\\ZIP\\test\\bbc.zip");
unzipFile("M:\\ZIP\\test\\bbc.zip", "M:\\ZIP\\test\\bb\\");
} catch (IOException e) {
e.printStackTrace();
}
}
}
注:
1、詳細情況請參照JDK文檔
2、JDK自身的ZIP包不支持中文,所以網上有很多介紹Apache下的解決方案,此處不作描述,文章太長了就更加臭了,另起一篇寫。
3、不支持密碼,網上另有支持密碼的項目,如果可能,另起文章介紹吧!
Java操作帶密碼的ZIP文件請參照: http://www.linuxidc.com/Linux/2014-11/109059.htm