Java對zip格式壓縮和解壓縮java
經過使用java的相關類能夠實現對文件或文件夾的壓縮,以及對壓縮文件的解壓。 算法
1.1 ZIP和GZIP的區別 apache
gzip是一種文件壓縮工具(或該壓縮工具產生的壓縮文件格式),它的設計目標是處理單個的文件。gzip在壓縮文件中的數據時使用的就是zlib。爲了保存與文件屬性有關的信息,gzip須要在壓縮文件(*.gz)中保存更多的頭信息內容,而zlib不用考慮這一點。但gzip只適用於單個文件,因此咱們在UNIX/Linux上常常看到的壓縮包後綴都是*.tar.gz或*.tgz,也就是先用tar把多個文件打包成單個文件,再用gzip壓縮的結果。
zip只是一種數據結構,跟rar同類型。zip是適用於壓縮多個文件的格式(相應的工具備PkZip和WinZip等),所以,zip文件還要進一步包含文件目錄結構的信息,比gzip的頭信息更多。但須要注意,zip格式可採用多種壓縮算法,咱們常見的zip文件大多不是用zlib的算法壓縮的,其壓縮數據的格式與gzip大不同。 數據結構
1.2相關類與接口: 工具
Checksum 接口:表示數據校驗和的接口,被類Adler32和CRC32實現
Adler32 :使用Alder32算法來計算Checksum數目
CRC32 :使用CRC32算法來計算Checksum數目 編碼
CheckedInputStream :InputStream派生類,可獲得輸入流的校驗和Checksum,用於校驗數據的完整性
CheckedOutputStream :OutputStream派生類,可獲得輸出流的校驗Checksum, 用於校驗數據的完整性 spa
DeflaterOutputStream :壓縮類的基類。
ZipOutputStream :DeflaterOutputStream的一個子類,把數據壓縮成Zip文件格式
GZIPOutputStream :DeflaterOutputStream的一個子類,把數據壓縮成GZip文件格式 設計
InflaterInputStream :解壓縮類的基類
ZipInputStream :InflaterInputStream的一個子類,能解壓縮Zip格式的數據
GZIPInputStream :InflaterInputStream的一個子類,能解壓縮Zip格式的數據 接口
ZipEntry 類:表示 ZIP 文件條目
ZipFile 類:此類用於從 ZIP 文件讀取條目 ip
1.3 壓縮文件
下面實例咱們使用了apache的zip工具包(所在包爲ant.jar ),由於java類型自帶的不支持中文路徑,不過二者使用的方式是同樣的,只是apache壓縮工具多了設置編碼方式的接口,其餘基本上是同樣的。另外,若是使用org.apache.tools.zip.ZipOutputStream來壓縮的話,咱們只能使用org.apache.tools.zip.ZipEntry來解壓,而不能使用java.util.zip.ZipInputStream來解壓讀取了,固然apache並未提供ZipInputStream類。
public static void compress(String srcFilePath, String destFilePath) {
File src = new File(srcFilePath);
if (!src.exists()) {
throw new RuntimeException(srcFilePath + "不存在");
}
File zipFile = new File(destFilePath);
try {
FileOutputStream fos = new FileOutputStream(zipFile);
CheckedOutputStream cos = new CheckedOutputStream(fos, new CRC32());
ZipOutputStream zos = new ZipOutputStream(cos);
String baseDir = "";
compressbyType(src, zos, baseDir);
zos.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static void compressbyType(File src, ZipOutputStream zos,
String baseDir) {
if (!src.exists())
return;
System.out.println("壓縮" + baseDir + src.getName());
if (src.isFile()) {
compressFile(src, zos, baseDir);
} else if (src.isDirectory()) {
compressDir(src, zos, baseDir);
}
}
/**
* 壓縮文件
*
*/
private static void compressFile(File file, ZipOutputStream zos,
String baseDir) {
if (!file.exists())
return;
try {
BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(file));
ZipEntry entry = new ZipEntry(baseDir + file.getName());
zos.putNextEntry(entry);
int count;
byte[] buf = new byte[BUFSIZE];
while ((count = bis.read(buf)) != -1) {
zos.write(buf, 0, count);
}
bis.close();
} catch (Exception e) {
// TODO: handle exception
}
}
/**
* 壓縮文件夾
*
*/
private static void compressDir(File dir, ZipOutputStream zos,
String baseDir) {
if (!dir.exists())
return;
File[] files = dir.listFiles();
if(files.length == 0){
try {
zos.putNextEntry(new ZipEntry(baseDir + dir.getName()
+ File.separator));
} catch (IOException e) {
e.printStackTrace();
}
}
for (File file : files) {
compressbyType(file, zos, baseDir + dir.getName() + File.separator);
}
}
總結步驟:
FileOutputStream fos = new FileOutputStream(zipFile);
CheckedOutputStream cos = new CheckedOutputStream(fos, new CRC32());
ZipOutputStream zos = new ZipOutputStream(cos);
ZipEntry entry = new ZipEntry(baseDir + file.getName());
而後將條目增長到ZipOutputStream中,
zos.putNextEntry(entry);
最後再調用要寫入條目對應文件的輸入流讀取文件內容寫入到壓縮文件中。
BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(file));
ZipEntry entry = new ZipEntry(baseDir + file.getName());
zos.putNextEntry(entry);
int count;
byte[] buf = new byte[BUFSIZE];
while ((count = bis.read(buf)) != -1) {
zos.write(buf, 0, count);
}
注意:若是是空目錄直接zos.putNextEntry(new ZipEntry(baseDir + dir.getName()+ File.separator))並不用寫入文件內容,其中最主要的涉及到目錄的壓縮的,就是這一句話 out.putNextEntry(new ZipEntry(base + "/")); //放入一級目錄 (防止空目錄被丟棄)
1.4 解壓zip文件
public static void decompress(String srcPath, String dest) throws Exception {
File file = new File(srcPath);
if (!file.exists()) {
throw new RuntimeException(srcPath + "所指文件不存在");
}
ZipFile zf = new ZipFile(file);
Enumeration entries = zf.getEntries();
ZipEntry entry = null;
while (entries.hasMoreElements()) {
entry = (ZipEntry) entries.nextElement();
System.out.println("解壓" + entry.getName());
if (entry.isDirectory()) {
String dirPath = dest + File.separator + entry.getName();
File dir = new File(dirPath);
dir.mkdirs();
} else {
// 表示文件
File f = new File(dest + File.separator + entry.getName());
if (!f.exists()) {
String dirs = FileUtils.getParentPath(f);
File parentDir = new File(dirs);
parentDir.mkdirs();
}
f.createNewFile();
// 將壓縮文件內容寫入到這個文件中
InputStream is = zf.getInputStream(entry);
FileOutputStream fos = new FileOutputStream(f);
int count;
byte[] buf = new byte[8192];
while ((count = is.read(buf)) != -1) {
fos.write(buf, 0, count);
}
is.close();
fos.close();
}
}
}