Java压缩技术(四) GZIP——Java原生实现

来源:互联网 发布:北京口语培训班 知乎 编辑:程序博客网 时间:2024/05/16 12:52

JavaEye的朋友跟我说:“你一口气把ZIP压缩和解压缩都写到一个帖子里,我看起来很累,不如分开好阅读”。ok,面向读者需求,我做调整,这里单说ZIP解压缩! 

相关链接: 
Java压缩技术(一) ZLib 
Java压缩技术(二) ZIP压缩——Java原生实现 
Java压缩技术(三) ZIP解压缩——Java原生实现 
Java压缩技术(四) GZIP——Java原生实现 
Java压缩技术(五) GZIP相关——浏览器解析 
Java压缩技术(六) BZIP2——Commons实现 
Java压缩技术(七) TAR——Commons实现 


解压缩与压缩运作方式相反,原理大抵相同,由ZipInputStream通过read方法对数据解压,同时需要通过CheckedInputStream设置冗余校验码,如: 

Java代码  收藏代码
  1. CheckedInputStream cis = new CheckedInputStream(new FileInputStream(  
  2.         srcFile), new CRC32());  
  3.   
  4. ZipInputStream zis = new ZipInputStream(cis);  


需要注意的是,在构建解压文件时,需要考虑目录的自动创建,这里通过递归方式逐层创建父目录,如下所示: 

Java代码  收藏代码
  1. /** 
  2.  * 文件探针 
  3.  *  
  4.  *  
  5.  * 当父目录不存在时,创建目录! 
  6.  *  
  7.  *  
  8.  * @param dirFile 
  9.  */  
  10. private static void fileProber(File dirFile) {  
  11.   
  12.     File parentFile = dirFile.getParentFile();  
  13.     if (!parentFile.exists()) {  
  14.   
  15.         // 递归寻找上级目录  
  16.         fileProber(parentFile);  
  17.   
  18.         parentFile.mkdir();  
  19.     }  
  20.   
  21. }  


在压缩的时候,我们是将一个一个文件作为压缩添加项(ZipEntry)添加至压缩包中,解压缩就要将一个一个压缩项从压缩包中提取出来,如下所示: 

Java代码  收藏代码
  1. /** 
  2.  * 文件 解压缩 
  3.  *  
  4.  * @param destFile 
  5.  *            目标文件 
  6.  * @param zis 
  7.  *            ZipInputStream 
  8.  * @throws Exception 
  9.  */  
  10. private static void decompress(File destFile, ZipInputStream zis)  
  11.         throws Exception {  
  12.   
  13.     ZipEntry entry = null;  
  14.     while ((entry = zis.getNextEntry()) != null) {  
  15.   
  16.         // 文件  
  17.         String dir = destFile.getPath() + File.separator + entry.getName();  
  18.   
  19.         File dirFile = new File(dir);  
  20.   
  21.         // 文件检查  
  22.         fileProber(dirFile);  
  23.   
  24.             if (entry.isDirectory()){  
  25.                 dirFile.mkdirs();  
  26.             } else {  
  27.             decompressFile(dirFile, zis);  
  28.             }  
  29.   
  30.             zis.closeEntry();  
  31.     }  
  32. }  




最核心的解压缩实现,其实与压缩实现非常相似,代码如下所示: 

Java代码  收藏代码
  1. /** 
  2.  * 文件解压缩 
  3.  *  
  4.  * @param destFile 
  5.  *            目标文件 
  6.  * @param zis 
  7.  *            ZipInputStream 
  8.  * @throws Exception 
  9.  */  
  10. private static void decompressFile(File destFile, ZipInputStream zis)  
  11.         throws Exception {  
  12.   
  13.     BufferedOutputStream bos = new BufferedOutputStream(  
  14.             new FileOutputStream(destFile));  
  15.   
  16.     int count;  
  17.     byte data[] = new byte[BUFFER];  
  18.     while ((count = zis.read(data, 0, BUFFER)) != -1) {  
  19.         bos.write(data, 0, count);  
  20.     }  
  21.   
  22.     bos.close();  
  23. }  




来个完整的解压缩实现,代码如下: 

Java代码  收藏代码
  1. /** 
  2.  * 2010-4-12 
  3.  */  
  4. package org.zlex.commons.io;  
  5.   
  6. import java.io.BufferedInputStream;  
  7. import java.io.BufferedOutputStream;  
  8. import java.io.File;  
  9. import java.io.FileInputStream;  
  10. import java.io.FileOutputStream;  
  11. import java.util.zip.CRC32;  
  12. import java.util.zip.CheckedInputStream;  
  13. import java.util.zip.CheckedOutputStream;  
  14. import java.util.zip.ZipEntry;  
  15. import java.util.zip.ZipInputStream;  
  16. import java.util.zip.ZipOutputStream;  
  17.   
  18. /** 
  19.  * ZIP压缩工具 
  20.  *  
  21.  * @author 梁栋    
  22.  * @since 1.0 
  23.  */  
  24. public class ZipUtils {  
  25.   
  26.     public static final String EXT = ".zip";  
  27.     private static final String BASE_DIR = "";  
  28.     private static final String PATH = File.separator;  
  29.     private static final int BUFFER = 1024;  
  30.   
  31.     /** 
  32.      * 文件 解压缩 
  33.      *  
  34.      * @param srcPath 
  35.      *            源文件路径 
  36.      *  
  37.      * @throws Exception 
  38.      */  
  39.     public static void decompress(String srcPath) throws Exception {  
  40.         File srcFile = new File(srcPath);  
  41.   
  42.         decompress(srcFile);  
  43.     }  
  44.   
  45.     /** 
  46.      * 解压缩 
  47.      *  
  48.      * @param srcFile 
  49.      * @throws Exception 
  50.      */  
  51.     public static void decompress(File srcFile) throws Exception {  
  52.         String basePath = srcFile.getParent();  
  53.         decompress(srcFile, basePath);  
  54.     }  
  55.   
  56.     /** 
  57.      * 解压缩 
  58.      *  
  59.      * @param srcFile 
  60.      * @param destFile 
  61.      * @throws Exception 
  62.      */  
  63.     public static void decompress(File srcFile, File destFile) throws Exception {  
  64.   
  65.         CheckedInputStream cis = new CheckedInputStream(new FileInputStream(  
  66.                 srcFile), new CRC32());  
  67.   
  68.         ZipInputStream zis = new ZipInputStream(cis);  
  69.   
  70.         decompress(destFile, zis);  
  71.   
  72.         zis.close();  
  73.   
  74.     }  
  75.   
  76.     /** 
  77.      * 解压缩 
  78.      *  
  79.      * @param srcFile 
  80.      * @param destPath 
  81.      * @throws Exception 
  82.      */  
  83.     public static void decompress(File srcFile, String destPath)  
  84.             throws Exception {  
  85.         decompress(srcFile, new File(destPath));  
  86.   
  87.     }  
  88.   
  89.     /** 
  90.      * 文件 解压缩 
  91.      *  
  92.      * @param srcPath 
  93.      *            源文件路径 
  94.      * @param destPath 
  95.      *            目标文件路径 
  96.      * @throws Exception 
  97.      */  
  98.     public static void decompress(String srcPath, String destPath)  
  99.             throws Exception {  
  100.   
  101.         File srcFile = new File(srcPath);  
  102.         decompress(srcFile, destPath);  
  103.     }  
  104.   
  105.     /** 
  106.      * 文件 解压缩 
  107.      *  
  108.      * @param destFile 
  109.      *            目标文件 
  110.      * @param zis 
  111.      *            ZipInputStream 
  112.      * @throws Exception 
  113.      */  
  114.     private static void decompress(File destFile, ZipInputStream zis)  
  115.             throws Exception {  
  116.   
  117.         ZipEntry entry = null;  
  118.         while ((entry = zis.getNextEntry()) != null) {  
  119.   
  120.             // 文件  
  121.             String dir = destFile.getPath() + File.separator + entry.getName();  
  122.   
  123.             File dirFile = new File(dir);  
  124.   
  125.             // 文件检查  
  126.             fileProber(dirFile);  
  127.   
  128.             if (entry.isDirectory()) {  
  129.                 dirFile.mkdirs();  
  130.             } else {  
  131.                 decompressFile(dirFile, zis);  
  132.             }  
  133.   
  134.             zis.closeEntry();  
  135.         }  
  136.     }  
  137.   
  138.     /** 
  139.      * 文件探针 
  140.      *  
  141.      *  
  142.      * 当父目录不存在时,创建目录! 
  143.      *  
  144.      *  
  145.      * @param dirFile 
  146.      */  
  147.     private static void fileProber(File dirFile) {  
  148.   
  149.         File parentFile = dirFile.getParentFile();  
  150.         if (!parentFile.exists()) {  
  151.   
  152.             // 递归寻找上级目录  
  153.             fileProber(parentFile);  
  154.   
  155.             parentFile.mkdir();  
  156.         }  
  157.   
  158.     }  
  159.   
  160.     /** 
  161.      * 文件解压缩 
  162.      *  
  163.      * @param destFile 
  164.      *            目标文件 
  165.      * @param zis 
  166.      *            ZipInputStream 
  167.      * @throws Exception 
  168.      */  
  169.     private static void decompressFile(File destFile, ZipInputStream zis)  
  170.             throws Exception {  
  171.   
  172.         BufferedOutputStream bos = new BufferedOutputStream(  
  173.                 new FileOutputStream(destFile));  
  174.   
  175.         int count;  
  176.         byte data[] = new byte[BUFFER];  
  177.         while ((count = zis.read(data, 0, BUFFER)) != -1) {  
  178.             bos.write(data, 0, count);  
  179.         }  
  180.   
  181.         bos.close();  
  182.     }  
  183.   
  184. }  




其实,理解了ZIP的工作原理,这些代码看起来很好懂! 

把刚才做的压缩文件再用上述代码解开看看,测试用例如下: 

Java代码  收藏代码
  1. /** 
  2.  * 2010-4-12 
  3.  */  
  4. package org.zlex.commons.io;  
  5.   
  6. import static org.junit.Assert.*;  
  7.   
  8. import org.junit.Test;  
  9.   
  10. /** 
  11.  *  
  12.  * @author 梁栋 
  13.  * @version 1.0 
  14.  * @since 1.0 
  15.  */  
  16. public class ZipUtilsTest {  
  17.   
  18.     /** 
  19.      *   
  20.      */  
  21.     @Test  
  22.     public void test() throws Exception {  
  23.         // 解压到指定目录  
  24.         ZipUtils.decompress("d:\\f.txt.zip""d:\\ff");  
  25.         // 解压到当前目录  
  26.         ZipUtils.decompress("d:\\fd.zip");  
  27.     }  
  28.   
  29. }  


完整代码详见附件! 

java原生的ZIP实现虽然在压缩时会因与系统字符集不符产生中文乱码,但在解压缩后,字符集即可恢复。 

除了java原生的ZIP实现外,commons和ant也提供了相应的ZIP算法实现,有机会我再一一介绍! 

0 0