相關鏈接:
Java壓縮技術(一) ZLib
Java壓縮技術(二) ZIP壓縮——Java原生實現
Java壓縮技術(三) ZIP解壓縮——Java原生實現
Java壓縮技術(四) GZIP——Java原生實現
Java壓縮技術(五) GZIP相關——瀏覽器解析
Java壓縮技術(六) BZIP2——Commons實現
Java壓縮技術(七) TAR——Commons實現
解壓縮與壓縮運作方式相反,原理大抵相同,由ZipInputStream通過read方法對數據解壓,同時需要通過CheckedInputStream設置冗餘校驗碼,如:
- CheckedInputStream cis = new CheckedInputStream(new FileInputStream(
- srcFile), new CRC32());
- ZipInputStream zis = new ZipInputStream(cis);
需要注意的是,在構建解壓文件時,需要考慮目錄的自動創建,這裏通過遞歸方式逐層創建父目錄,如下所示:
- /**
- * 文件探針
- *
- *
- * 當父目錄不存在時,創建目錄!
- *
- *
- * @param dirFile
- */
- private static void fileProber(File dirFile) {
- File parentFile = dirFile.getParentFile();
- if (!parentFile.exists()) {
- // 遞歸尋找上級目錄
- fileProber(parentFile);
- parentFile.mkdir();
- }
- }
在壓縮的時候,我們是將一個一個文件作爲壓縮添加項(ZipEntry)添加至壓縮包中,解壓縮就要將一個一個壓縮項從壓縮包中提取出來,如下所示:
- /**
- * 文件 解壓縮
- *
- * @param destFile
- * 目標文件
- * @param zis
- * ZipInputStream
- * @throws Exception
- */
- private static void decompress(File destFile, ZipInputStream zis)
- throws Exception {
- ZipEntry entry = null;
- while ((entry = zis.getNextEntry()) != null) {
- // 文件
- String dir = destFile.getPath() + File.separator + entry.getName();
- File dirFile = new File(dir);
- // 文件檢查
- fileProber(dirFile);
- if (entry.isDirectory()){
- dirFile.mkdirs();
- } else {
- decompressFile(dirFile, zis);
- }
- zis.closeEntry();
- }
- }
最核心的解壓縮實現,其實與壓縮實現非常相似,代碼如下所示:
- /**
- * 文件解壓縮
- *
- * @param destFile
- * 目標文件
- * @param zis
- * ZipInputStream
- * @throws Exception
- */
- private static void decompressFile(File destFile, ZipInputStream zis)
- throws Exception {
- BufferedOutputStream bos = new BufferedOutputStream(
- new FileOutputStream(destFile));
- int count;
- byte data[] = new byte[BUFFER];
- while ((count = zis.read(data, 0, BUFFER)) != -1) {
- bos.write(data, 0, count);
- }
- bos.close();
- }
來個完整的解壓縮實現,代碼如下:
- /**
- * 2010-4-12
- */
- package org.zlex.commons.io;
- import java.io.BufferedInputStream;
- import java.io.BufferedOutputStream;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.util.zip.CRC32;
- import java.util.zip.CheckedInputStream;
- import java.util.zip.CheckedOutputStream;
- import java.util.zip.ZipEntry;
- import java.util.zip.ZipInputStream;
- import java.util.zip.ZipOutputStream;
- /**
- * ZIP壓縮工具
- *
- * @author 樑棟
- * @since 1.0
- */
- public class ZipUtils {
- public static final String EXT = ".zip";
- private static final String BASE_DIR = "";
- private static final String PATH = File.separator;
- private static final int BUFFER = 1024;
- /**
- * 文件 解壓縮
- *
- * @param srcPath
- * 源文件路徑
- *
- * @throws Exception
- */
- public static void decompress(String srcPath) throws Exception {
- File srcFile = new File(srcPath);
- decompress(srcFile);
- }
- /**
- * 解壓縮
- *
- * @param srcFile
- * @throws Exception
- */
- public static void decompress(File srcFile) throws Exception {
- String basePath = srcFile.getParent();
- decompress(srcFile, basePath);
- }
- /**
- * 解壓縮
- *
- * @param srcFile
- * @param destFile
- * @throws Exception
- */
- public static void decompress(File srcFile, File destFile) throws Exception {
- CheckedInputStream cis = new CheckedInputStream(new FileInputStream(
- srcFile), new CRC32());
- ZipInputStream zis = new ZipInputStream(cis);
- decompress(destFile, zis);
- zis.close();
- }
- /**
- * 解壓縮
- *
- * @param srcFile
- * @param destPath
- * @throws Exception
- */
- public static void decompress(File srcFile, String destPath)
- throws Exception {
- decompress(srcFile, new File(destPath));
- }
- /**
- * 文件 解壓縮
- *
- * @param srcPath
- * 源文件路徑
- * @param destPath
- * 目標文件路徑
- * @throws Exception
- */
- public static void decompress(String srcPath, String destPath)
- throws Exception {
- File srcFile = new File(srcPath);
- decompress(srcFile, destPath);
- }
- /**
- * 文件 解壓縮
- *
- * @param destFile
- * 目標文件
- * @param zis
- * ZipInputStream
- * @throws Exception
- */
- private static void decompress(File destFile, ZipInputStream zis)
- throws Exception {
- ZipEntry entry = null;
- while ((entry = zis.getNextEntry()) != null) {
- // 文件
- String dir = destFile.getPath() + File.separator + entry.getName();
- File dirFile = new File(dir);
- // 文件檢查
- fileProber(dirFile);
- if (entry.isDirectory()) {
- dirFile.mkdirs();
- } else {
- decompressFile(dirFile, zis);
- }
- zis.closeEntry();
- }
- }
- /**
- * 文件探針
- *
- *
- * 當父目錄不存在時,創建目錄!
- *
- *
- * @param dirFile
- */
- private static void fileProber(File dirFile) {
- File parentFile = dirFile.getParentFile();
- if (!parentFile.exists()) {
- // 遞歸尋找上級目錄
- fileProber(parentFile);
- parentFile.mkdir();
- }
- }
- /**
- * 文件解壓縮
- *
- * @param destFile
- * 目標文件
- * @param zis
- * ZipInputStream
- * @throws Exception
- */
- private static void decompressFile(File destFile, ZipInputStream zis)
- throws Exception {
- BufferedOutputStream bos = new BufferedOutputStream(
- new FileOutputStream(destFile));
- int count;
- byte data[] = new byte[BUFFER];
- while ((count = zis.read(data, 0, BUFFER)) != -1) {
- bos.write(data, 0, count);
- }
- bos.close();
- }
- }
其實,理解了ZIP的工作原理,這些代碼看起來很好懂!
把剛纔做的壓縮文件再用上述代碼解開看看,測試用例如下:
- /**
- * 2010-4-12
- */
- package org.zlex.commons.io;
- import static org.junit.Assert.*;
- import org.junit.Test;
- /**
- *
- * @author 樑棟
- * @version 1.0
- * @since 1.0
- */
- public class ZipUtilsTest {
- /**
- *
- */
- @Test
- public void test() throws Exception {
- // 解壓到指定目錄
- ZipUtils.decompress("d:\\f.txt.zip", "d:\\ff");
- // 解壓到當前目錄
- ZipUtils.decompress("d:\\fd.zip");
- }
- }
java原生的ZIP實現雖然在壓縮時會因與系統字符集不符產生中文亂碼,但在解壓縮後,字符集即可恢復。
除了java原生的ZIP實現外,commons和ant也提供了相應的ZIP算法實現,有機會我再一一介紹!