守望者--AIR技术交流

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

搜索
热搜: ANE FlasCC 炼金术
查看: 4885|回复: 8
打印 上一主题 下一主题

[后台技术] Java压缩技术

[复制链接]
  • TA的每日心情
    擦汗
    2018-4-10 15:18
  • 签到天数: 447 天

    [LV.9]以坛为家II

    1742

    主题

    2094

    帖子

    13万

    积分

    超级版主

    Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18

    威望
    562
    贡献
    29
    金币
    52694
    钢镚
    1422

    开源英雄守望者

    跳转到指定楼层
    楼主
    发表于 2015-1-11 13:16:25 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    Java压缩技术(一) ZLib


    应好友需要,整理一下Java的压缩算法,先从ZLib开始。


    有关ZLib可参见官方主页 http://www.zlib.net/
    ZLib可以简单的理解为压缩/解压缩算法,它与ZIP、RAR等归档算法有所不同,与bzip2比较接近。

    压缩工具代码如下:

    1. /**
    2. * 2009-9-9
    3. */  
    4. package org.zlex.commons.io;  
    5.   
    6. import java.io.ByteArrayOutputStream;  
    7. import java.io.IOException;  
    8. import java.io.InputStream;  
    9. import java.io.OutputStream;  
    10. import java.util.zip.Deflater;  
    11. import java.util.zip.DeflaterOutputStream;  
    12. import java.util.zip.Inflater;  
    13. import java.util.zip.InflaterInputStream;  
    14.   
    15. /**
    16. * ZLib压缩工具
    17. *  
    18. * @author <a href="mailto:zlex.dongliang@gmail.com">梁栋</a>
    19. * @version 1.0
    20. * @since 1.0
    21. */  
    22. public abstract class ZLibUtils {  
    23.   
    24.     /**
    25.      * 压缩
    26.      *  
    27.      * @param data
    28.      *            待压缩数据
    29.      * @return byte[] 压缩后的数据
    30.      */  
    31.     public static byte[] compress(byte[] data) {  
    32.         byte[] output = new byte[0];  
    33.   
    34.         Deflater compresser = new Deflater();  
    35.   
    36.         compresser.reset();  
    37.         compresser.setInput(data);  
    38.         compresser.finish();  
    39.         ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length);  
    40.         try {  
    41.             byte[] buf = new byte[1024];  
    42.             while (!compresser.finished()) {  
    43.                 int i = compresser.deflate(buf);  
    44.                 bos.write(buf, 0, i);  
    45.             }  
    46.             output = bos.toByteArray();  
    47.         } catch (Exception e) {  
    48.             output = data;  
    49.             e.printStackTrace();  
    50.         } finally {  
    51.             try {  
    52.                 bos.close();  
    53.             } catch (IOException e) {  
    54.                 e.printStackTrace();  
    55.             }  
    56.         }  
    57.         compresser.end();  
    58.         return output;  
    59.     }  
    60.   
    61.     /**
    62.      * 压缩
    63.      *  
    64.      * @param data
    65.      *            待压缩数据
    66.      *  
    67.      * @param os
    68.      *            输出流
    69.      */  
    70.     public static void compress(byte[] data, OutputStream os) {  
    71.         DeflaterOutputStream dos = new DeflaterOutputStream(os);  
    72.   
    73.         try {  
    74.             dos.write(data, 0, data.length);  
    75.   
    76.             dos.finish();  
    77.   
    78.             dos.flush();  
    79.         } catch (IOException e) {  
    80.             e.printStackTrace();  
    81.         }  
    82.     }  
    83.   
    84.     /**
    85.      * 解压缩
    86.      *  
    87.      * @param data
    88.      *            待压缩的数据
    89.      * @return byte[] 解压缩后的数据
    90.      */  
    91.     public static byte[] decompress(byte[] data) {  
    92.         byte[] output = new byte[0];  
    93.   
    94.         Inflater decompresser = new Inflater();  
    95.         decompresser.reset();  
    96.         decompresser.setInput(data);  
    97.   
    98.         ByteArrayOutputStream o = new ByteArrayOutputStream(data.length);  
    99.         try {  
    100.             byte[] buf = new byte[1024];  
    101.             while (!decompresser.finished()) {  
    102.                 int i = decompresser.inflate(buf);  
    103.                 o.write(buf, 0, i);  
    104.             }  
    105.             output = o.toByteArray();  
    106.         } catch (Exception e) {  
    107.             output = data;  
    108.             e.printStackTrace();  
    109.         } finally {  
    110.             try {  
    111.                 o.close();  
    112.             } catch (IOException e) {  
    113.                 e.printStackTrace();  
    114.             }  
    115.         }  
    116.   
    117.         decompresser.end();  
    118.         return output;  
    119.     }  
    120.   
    121.     /**
    122.      * 解压缩
    123.      *  
    124.      * @param is
    125.      *            输入流
    126.      * @return byte[] 解压缩后的数据
    127.      */  
    128.     public static byte[] decompress(InputStream is) {  
    129.         InflaterInputStream iis = new InflaterInputStream(is);  
    130.         ByteArrayOutputStream o = new ByteArrayOutputStream(1024);  
    131.         try {  
    132.             int i = 1024;  
    133.             byte[] buf = new byte[i];  
    134.   
    135.             while ((i = iis.read(buf, 0, i)) > 0) {  
    136.                 o.write(buf, 0, i);  
    137.             }  
    138.   
    139.         } catch (IOException e) {  
    140.             e.printStackTrace();  
    141.         }  
    142.         return o.toByteArray();  
    143.     }  
    144. }  
    复制代码
    测试用例代码如下:
    1. /**
    2. * 2009-9-9
    3. */  
    4. package org.zlex.commons.io;  
    5.   
    6. import static org.junit.Assert.*;  
    7.   
    8. import java.io.File;  
    9. import java.io.FileInputStream;  
    10. import java.io.FileOutputStream;  
    11.   
    12. import org.junit.Test;  
    13.   
    14. /**
    15. * ZLib压缩测试用例
    16. *  
    17. * @author <a href="mailto:zlex.dongliang@gmail.com">梁栋</a>
    18. * @version 1.0
    19. * @since 1.0
    20. */  
    21. public class ZLibUtilsTest {  
    22.   
    23.     @Test  
    24.     public final void testBytes() {  
    25.         System.err.println("字节压缩/解压缩测试");  
    26.         String inputStr = "snowolf@zlex.org;dongliang@zlex.org;zlex.dongliang@zlex.org";  
    27.         System.err.println("输入字符串:\t" + inputStr);  
    28.         byte[] input = inputStr.getBytes();  
    29.         System.err.println("输入字节长度:\t" + input.length);  
    30.   
    31.         byte[] data = ZLibUtils.compress(input);  
    32.         System.err.println("压缩后字节长度:\t" + data.length);  
    33.   
    34.         byte[] output = ZLibUtils.decompress(data);  
    35.         System.err.println("解压缩后字节长度:\t" + output.length);  
    36.         String outputStr = new String(output);  
    37.         System.err.println("输出字符串:\t" + outputStr);  
    38.   
    39.         assertEquals(inputStr, outputStr);  
    40.     }  
    41.   
    42.     @Test  
    43.     public final void testFile() {  
    44.         String filename = "zlib";  
    45.         File file = new File(filename);  
    46.         System.err.println("文件压缩/解压缩测试");  
    47.         String inputStr = "snowolf@zlex.org;dongliang@zlex.org;zlex.dongliang@zlex.org";  
    48.         System.err.println("输入字符串:\t" + inputStr);  
    49.         byte[] input = inputStr.getBytes();  
    50.         System.err.println("输入字节长度:\t" + input.length);  
    51.   
    52.         try {  
    53.   
    54.             FileOutputStream fos = new FileOutputStream(file);  
    55.             ZLibUtils.compress(input, fos);  
    56.             fos.close();  
    57.             System.err.println("压缩后字节长度:\t" + file.length());  
    58.         } catch (Exception e) {  
    59.             fail(e.getMessage());  
    60.         }  
    61.   
    62.         byte[] output = null;  
    63.   
    64.         try {  
    65.             FileInputStream fis = new FileInputStream(file);  
    66.             output = ZLibUtils.decompress(fis);  
    67.             fis.close();  
    68.   
    69.         } catch (Exception e) {  
    70.             fail(e.getMessage());  
    71.         }  
    72.         System.err.println("解压缩后字节长度:\t" + output.length);  
    73.         String outputStr = new String(output);  
    74.         System.err.println("输出字符串:\t" + outputStr);  
    75.   
    76.         assertEquals(inputStr, outputStr);  
    77.     }  
    78. }  
    复制代码
    输入结果
    1. 字节压缩/解压缩测试  
    2. 输入字符串:  snowolf@zlex.org;dongliang@zlex.org;zlex.dongliang@zlex.org  
    3. 输入字节长度: 59  
    4. 压缩后字节长度:    39  
    5. 解压缩后字节长度:   59  
    6. 输出字符串:  snowolf@zlex.org;dongliang@zlex.org;zlex.dongliang@zlex.org  
    7. 文件压缩/解压缩测试  
    8. 输入字符串:  snowolf@zlex.org;dongliang@zlex.org;zlex.dongliang@zlex.org  
    9. 输入字节长度: 59  
    10. 压缩后字节长度:    39  
    11. 解压缩后字节长度:   59  
    12. 输出字符串:  snowolf@zlex.org;dongliang@zlex.org;zlex.dongliang@zlex.org  
    复制代码
    应该怎么计算呢?原数据长度59字节,压缩后39字节,大约是33%的压缩率!

    ZLib压缩对大字节数据压缩,才能反映出压缩效果。
    先占个位儿,回头细致整理!



    本系列文章来自:http://snowolf.iteye.com/blog/465433
    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
    收藏收藏 分享分享 支持支持 反对反对 微信
    守望者AIR技术交流社区(www.airmyth.com)
    回复

    使用道具 举报

  • TA的每日心情
    擦汗
    2018-4-10 15:18
  • 签到天数: 447 天

    [LV.9]以坛为家II

    1742

    主题

    2094

    帖子

    13万

    积分

    超级版主

    Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18

    威望
    562
    贡献
    29
    金币
    52694
    钢镚
    1422

    开源英雄守望者

    沙发
     楼主| 发表于 2015-1-11 13:19:20 | 只看该作者

    Java压缩技术(二) ZIP压缩——Java原生实现

    Java压缩技术(二) ZIP压缩——Java原生实现


    去年整理了一篇ZLib算法Java实现(
    Java压缩技术(一) ZLib),一直惦记却没时间补充。今天得空,整理一下ZIP的java原生实现。
    看了几篇zip压缩算法的帖子,讲的算是比较细致了,但就是没有对应的解压缩实现,太惜败了! 我就喜欢没事做总结,稍作整理,将其收纳!
    查过相关资料后才知道,ZIP应该算作归档类的压缩算法,每一门学科都可深可浅!

    闲言少叙,先说ZIP压缩。
    zip压缩需要通过ZipOutputStream 执行write方法将压缩数据写到指定输出流中。
    注意,这里应先使用CheckedOutputStream 指定文件校验算法。(通常使用CRC32算法)。代码如下所示:
    1. CheckedOutputStream cos = new CheckedOutputStream(new FileOutputStream(destPath), new CRC32());  
    2. ZipOutputStream zos = new ZipOutputStream(cos);  
    复制代码
    接下来,需要将待压缩文件以ZipEntry的方式追加到压缩文件中,如下所示:
    1. /**
    2. * 压缩包内文件名定义
    3. *  
    4. * <pre>
    5. * 如果有多级目录,那么这里就需要给出包含目录的文件名
    6. * 如果用WinRAR打开压缩包,中文名将显示为乱码
    7. * </pre>
    8. */  
    9. ZipEntry entry = new ZipEntry(dir + file.getName());  
    10.   
    11. zos.putNextEntry(entry);  
    复制代码
    ZipEntry就是压缩包中的每一个实体!
    完成上述准备后,就可以执行压缩操作了。实际上,就是执行ZipOutputStream类的write方法,如下所示:
    1. BufferedInputStream bis = new BufferedInputStream(new FileInputStream(  
    2.         file));  
    3.   
    4. int count;  
    5. byte data[] = new byte[BUFFER];  
    6. while ((count = bis.read(data, 0, BUFFER)) != -1) {  
    7.     zos.write(data, 0, count);  
    8. }  
    9. bis.close();  
    复制代码
    当然,如果待添加的压缩项是一个目录。那么,需要通过递归的方式指定最终的压缩项。
    如果要添加一个空目录,注意使用符号"/"(String PATH="/";)作为添加项名字结尾符!

    递归构建目录压缩,代码如下:
    1. /**
    2. * 压缩
    3. *  
    4. * @param srcFile
    5. *            源路径
    6. * @param zos
    7. *            ZipOutputStream
    8. * @param basePath
    9. *            压缩包内相对路径
    10. * @throws Exception
    11. */  
    12. private static void compress(File srcFile, ZipOutputStream zos,  
    13.         String basePath) throws Exception {  
    14.     if (srcFile.isDirectory()) {  
    15.         compressDir(srcFile, zos, basePath);  
    16.     } else {  
    17.         compressFile(srcFile, zos, basePath);  
    18.     }  
    19. }  
    20.   
    21. /**
    22. * 压缩目录
    23. *  
    24. * @param dir
    25. * @param zos
    26. * @param basePath
    27. * @throws Exception
    28. */  
    29. private static void compressDir(File dir, ZipOutputStream zos,  
    30.         String basePath) throws Exception {  
    31.   
    32.     File[] files = dir.listFiles();  
    33.   
    34.     // 构建空目录  
    35.     if (files.length < 1) {  
    36.         ZipEntry entry = new ZipEntry(basePath + dir.getName() + PATH);  
    37.   
    38.         zos.putNextEntry(entry);  
    39.         zos.closeEntry();  
    40.     }  
    41.   
    42.     for (File file : files) {  
    43.         // 递归压缩  
    44.         compress(file, zos, basePath + dir.getName() + PATH);  
    45.     }  
    46. }  
    复制代码
    x是一个空目录,用WinRAR打开后,可以看到这个目录下还有一个空文件名文件!


    来个完整的压缩实现,代码如下所示:
    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  <a href="mailto:zlex.dongliang@gmail.com">梁栋</a>   
    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.   
    29.     // 符号"/"用来作为目录标识判断符  
    30.     private static final String PATH = "/";  
    31.     private static final int BUFFER = 1024;  
    32.   
    33.     /**
    34.      * 压缩
    35.      *  
    36.      * @param srcFile
    37.      * @throws Exception
    38.      */  
    39.     public static void compress(File srcFile) throws Exception {  
    40.         String name = srcFile.getName();  
    41.         String basePath = srcFile.getParent();  
    42.         String destPath = basePath + name + EXT;  
    43.         compress(srcFile, destPath);  
    44.     }  
    45.   
    46.     /**
    47.      * 压缩
    48.      *  
    49.      * @param srcFile
    50.      *            源路径
    51.      * @param destPath
    52.      *            目标路径
    53.      * @throws Exception
    54.      */  
    55.     public static void compress(File srcFile, File destFile) throws Exception {  
    56.   
    57.         // 对输出文件做CRC32校验  
    58.         CheckedOutputStream cos = new CheckedOutputStream(new FileOutputStream(  
    59.                 destFile), new CRC32());  
    60.   
    61.         ZipOutputStream zos = new ZipOutputStream(cos);  
    62.   
    63.         compress(srcFile, zos, BASE_DIR);  
    64.   
    65.         zos.flush();  
    66.         zos.close();  
    67.     }  
    68.   
    69.     /**
    70.      * 压缩文件
    71.      *  
    72.      * @param srcFile
    73.      * @param destPath
    74.      * @throws Exception
    75.      */  
    76.     public static void compress(File srcFile, String destPath) throws Exception {  
    77.         compress(srcFile, new File(destPath));  
    78.     }  
    79.   
    80.     /**
    81.      * 压缩
    82.      *  
    83.      * @param srcFile
    84.      *            源路径
    85.      * @param zos
    86.      *            ZipOutputStream
    87.      * @param basePath
    88.      *            压缩包内相对路径
    89.      * @throws Exception
    90.      */  
    91.     private static void compress(File srcFile, ZipOutputStream zos,  
    92.             String basePath) throws Exception {  
    93.         if (srcFile.isDirectory()) {  
    94.             compressDir(srcFile, zos, basePath);  
    95.         } else {  
    96.             compressFile(srcFile, zos, basePath);  
    97.         }  
    98.     }  
    99.   
    100.     /**
    101.      * 压缩
    102.      *  
    103.      * @param srcPath
    104.      * @throws Exception
    105.      */  
    106.     public static void compress(String srcPath) throws Exception {  
    107.         File srcFile = new File(srcPath);  
    108.   
    109.         compress(srcFile);  
    110.     }  
    111.   
    112.     /**
    113.      * 文件压缩
    114.      *  
    115.      * @param srcPath
    116.      *            源文件路径
    117.      * @param destPath
    118.      *            目标文件路径
    119.      *  
    120.      */  
    121.     public static void compress(String srcPath, String destPath)  
    122.             throws Exception {  
    123.         File srcFile = new File(srcPath);  
    124.   
    125.         compress(srcFile, destPath);  
    126.     }  
    127.   
    128.     /**
    129.      * 压缩目录
    130.      *  
    131.      * @param dir
    132.      * @param zos
    133.      * @param basePath
    134.      * @throws Exception
    135.      */  
    136.     private static void compressDir(File dir, ZipOutputStream zos,  
    137.             String basePath) throws Exception {  
    138.   
    139.         File[] files = dir.listFiles();  
    140.   
    141.         // 构建空目录  
    142.         if (files.length < 1) {  
    143.             ZipEntry entry = new ZipEntry(basePath + dir.getName() + PATH);  
    144.   
    145.             zos.putNextEntry(entry);  
    146.             zos.closeEntry();  
    147.         }  
    148.   
    149.         for (File file : files) {  
    150.   
    151.             // 递归压缩  
    152.             compress(file, zos, basePath + dir.getName() + PATH);  
    153.   
    154.         }  
    155.     }  
    156.   
    157.     /**
    158.      * 文件压缩
    159.      *  
    160.      * @param file
    161.      *            待压缩文件
    162.      * @param zos
    163.      *            ZipOutputStream
    164.      * @param dir
    165.      *            压缩文件中的当前路径
    166.      * @throws Exception
    167.      */  
    168.     private static void compressFile(File file, ZipOutputStream zos, String dir)  
    169.             throws Exception {  
    170.   
    171.         /**
    172.          * 压缩包内文件名定义
    173.          *  
    174.          * <pre>
    175.          * 如果有多级目录,那么这里就需要给出包含目录的文件名
    176.          * 如果用WinRAR打开压缩包,中文名将显示为乱码
    177.          * </pre>
    178.          */  
    179.         ZipEntry entry = new ZipEntry(dir + file.getName());  
    180.   
    181.         zos.putNextEntry(entry);  
    182.   
    183.         BufferedInputStream bis = new BufferedInputStream(new FileInputStream(  
    184.                 file));  
    185.   
    186.         int count;  
    187.         byte data[] = new byte[BUFFER];  
    188.         while ((count = bis.read(data, 0, BUFFER)) != -1) {  
    189.             zos.write(data, 0, count);  
    190.         }  
    191.         bis.close();  
    192.   
    193.         zos.closeEntry();  
    194.     }  
    195.   
    196. }  
    复制代码
    来做个简单的测试:
    1. import static org.junit.Assert.*;  
    2.   
    3. import org.junit.Test;  
    4.   
    5. /**
    6. *  
    7. * @author 梁栋
    8. * @version 1.0
    9. * @since 1.0
    10. */  
    11. public class ZipUtilsTest {  
    12.   
    13.     /**
    14.      *   
    15.      */  
    16.     @Test  
    17.     public void test() throws Exception {  
    18.         // 压缩文件  
    19.         ZipUtils.compress("d:\\f.txt");  
    20.         // 压缩目录  
    21.         ZipUtils.compress("d:\\fd");  
    22.     }  
    23. }  
    复制代码
    现在用WinRAR打开看看,是不是效果几乎一致?

    当然,上述代码有所不足之处主要是中文名称乱码问题。用java原生ZIP实现压缩后得到的压缩包,与系统的字符集不同,文件/目录名将出现乱码。这是所有归档压缩都会遇到的问题。对于这种问题,Commons Copress提供了解决方案!

    对于解压缩,请关注后续内容!
    守望者AIR技术交流社区(www.airmyth.com)
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2018-4-10 15:18
  • 签到天数: 447 天

    [LV.9]以坛为家II

    1742

    主题

    2094

    帖子

    13万

    积分

    超级版主

    Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18

    威望
    562
    贡献
    29
    金币
    52694
    钢镚
    1422

    开源英雄守望者

    板凳
     楼主| 发表于 2015-1-11 13:24:59 | 只看该作者
    Java压缩技术(三) ZIP解压缩——Java原生实现


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

    解压缩与压缩运作方式相反,原理大抵相同,由ZipInputStream通过read方法对数据解压,同时需要通过CheckedInputStream设置冗余校验码,如:
    1. CheckedInputStream cis = new CheckedInputStream(new FileInputStream(  
    2.         srcFile), new CRC32());  
    3.   
    4. ZipInputStream zis = new ZipInputStream(cis);  
    复制代码
    需要注意的是,在构建解压文件时,需要考虑目录的自动创建,这里通过递归方式逐层创建父目录,如下所示:
    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)添加至压缩包中,解压缩就要将一个一个压缩项从压缩包中提取出来,如下所示:

    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. }  
    复制代码
    最核心的解压缩实现,其实与压缩实现非常相似,代码如下所示:
    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. }  
    复制代码
    来个完整的解压缩实现,代码如下:
    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的工作原理,这些代码看起来很好懂!

    把刚才做的压缩文件再用上述代码解开看看,测试用例如下:
    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算法实现,有机会我再一一介绍!

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    守望者AIR技术交流社区(www.airmyth.com)
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2018-4-10 15:18
  • 签到天数: 447 天

    [LV.9]以坛为家II

    1742

    主题

    2094

    帖子

    13万

    积分

    超级版主

    Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18

    威望
    562
    贡献
    29
    金币
    52694
    钢镚
    1422

    开源英雄守望者

    地板
     楼主| 发表于 2015-1-11 13:30:44 | 只看该作者

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

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

    趁着头脑清楚,抓紧时间继续整理!
    熟悉linux的朋友可能都用过文件压缩命令,譬如最为简单的gzip命令。


    GZIP常常用在linxu环境下,是一种非常简单的压缩算法。在Java实现API中,它仅仅包含两个实现类:GZIPInputStream和GZIPOutputStream。
    GZIPOutputStream类用于压缩
    GZIPInputStream类用于解压缩

    先说压缩实现,GZIPOutputStream只有一个方法用于压缩,就是带定长的write方法。简单调用如下文所示:
    1. /**
    2. * 数据压缩
    3. *  
    4. * @param is
    5. * @param os
    6. * @throws Exception
    7. */  
    8. public static void compress(InputStream is, OutputStream os)  
    9.         throws Exception {  
    10.   
    11.     GZIPOutputStream gos = new GZIPOutputStream(os);  
    12.   
    13.     int count;  
    14.     byte data[] = new byte[BUFFER];  
    15.     while ((count = is.read(data, 0, BUFFER)) != -1) {  
    16.         gos.write(data, 0, count);  
    17.     }  
    18.   
    19.     gos.finish();  
    20.   
    21.     gos.flush();  
    22.     gos.close();  
    23. }  
    复制代码
    记得完成操作后,调用finish方法和flush方法!

    核心的压缩实现就这么多!

    对于解压缩,GZIPInputStream也对应GZIPOutputStream提供了一个带定长的read方法。简单调用如下文所示:
    1. /**
    2. * 数据解压缩
    3. *  
    4. * @param is
    5. * @param os
    6. * @throws Exception
    7. */  
    8. public static void decompress(InputStream is, OutputStream os)  
    9.         throws Exception {  
    10.   
    11.     GZIPInputStream gis = new GZIPInputStream(is);  
    12.   
    13.     int count;  
    14.     byte data[] = new byte[BUFFER];  
    15.     while ((count = gis.read(data, 0, BUFFER)) != -1) {  
    16.         os.write(data, 0, count);  
    17.     }  
    18.   
    19.     gis.close();  
    20. }  
    复制代码
    就这么简单! 核心内容完毕!

    顺便补充一下,在liunx下操作gzip命令

    gzip file用于压缩,如gzip a.txt将得到文件a.txt.gz同时删除文件a.txt!
    gzip -d file.gz用于解压缩,如gzip -d a.txt.gz将得到文件a.txt同时删除文件a.txt.gz!

    根据这些特性,我补充了相应的文件操作实现,详见下文!

    完整实现:
    1. /**
    2. * 2010-4-13
    3. */  
    4. package org.zlex.commons.io;  
    5.   
    6. import java.io.ByteArrayInputStream;  
    7. import java.io.ByteArrayOutputStream;  
    8. import java.io.File;  
    9. import java.io.FileInputStream;  
    10. import java.io.FileOutputStream;  
    11. import java.io.InputStream;  
    12. import java.io.OutputStream;  
    13. import java.util.zip.GZIPInputStream;  
    14. import java.util.zip.GZIPOutputStream;  
    15.   
    16. /**
    17. * GZIP工具
    18. *  
    19. * @author <a href="mailto:zlex.dongliang@gmail.com">梁栋</a>
    20. * @since 1.0
    21. */  
    22. public abstract class GZipUtils {  
    23.   
    24.     public static final int BUFFER = 1024;  
    25.     public static final String EXT = ".gz";  
    26.   
    27.     /**
    28.      * 数据压缩
    29.      *  
    30.      * @param data
    31.      * @return
    32.      * @throws Exception
    33.      */  
    34.     public static byte[] compress(byte[] data) throws Exception {  
    35.         ByteArrayInputStream bais = new ByteArrayInputStream(data);  
    36.         ByteArrayOutputStream baos = new ByteArrayOutputStream();  
    37.   
    38.         // 压缩  
    39.         compress(bais, baos);  
    40.   
    41.         byte[] output = baos.toByteArray();  
    42.   
    43.         baos.flush();  
    44.         baos.close();  
    45.   
    46.         bais.close();  
    47.   
    48.         return output;  
    49.     }  
    50.   
    51.     /**
    52.      * 文件压缩
    53.      *  
    54.      * @param file
    55.      * @throws Exception
    56.      */  
    57.     public static void compress(File file) throws Exception {  
    58.         compress(file, true);  
    59.     }  
    60.   
    61.     /**
    62.      * 文件压缩
    63.      *  
    64.      * @param file
    65.      * @param delete
    66.      *            是否删除原始文件
    67.      * @throws Exception
    68.      */  
    69.     public static void compress(File file, boolean delete) throws Exception {  
    70.         FileInputStream fis = new FileInputStream(file);  
    71.         FileOutputStream fos = new FileOutputStream(file.getPath() + EXT);  
    72.   
    73.         compress(fis, fos);  
    74.   
    75.         fis.close();  
    76.         fos.flush();  
    77.         fos.close();  
    78.   
    79.         if (delete) {  
    80.             file.delete();  
    81.         }  
    82.     }  
    83.   
    84.     /**
    85.      * 数据压缩
    86.      *  
    87.      * @param is
    88.      * @param os
    89.      * @throws Exception
    90.      */  
    91.     public static void compress(InputStream is, OutputStream os)  
    92.             throws Exception {  
    93.   
    94.         GZIPOutputStream gos = new GZIPOutputStream(os);  
    95.   
    96.         int count;  
    97.         byte data[] = new byte[BUFFER];  
    98.         while ((count = is.read(data, 0, BUFFER)) != -1) {  
    99.             gos.write(data, 0, count);  
    100.         }  
    101.   
    102.         gos.finish();  
    103.   
    104.         gos.flush();  
    105.         gos.close();  
    106.     }  
    107.   
    108.     /**
    109.      * 文件压缩
    110.      *  
    111.      * @param path
    112.      * @throws Exception
    113.      */  
    114.     public static void compress(String path) throws Exception {  
    115.         compress(path, true);  
    116.     }  
    117.   
    118.     /**
    119.      * 文件压缩
    120.      *  
    121.      * @param path
    122.      * @param delete
    123.      *            是否删除原始文件
    124.      * @throws Exception
    125.      */  
    126.     public static void compress(String path, boolean delete) throws Exception {  
    127.         File file = new File(path);  
    128.         compress(file, delete);  
    129.     }  
    130.   
    131.     /**
    132.      * 数据解压缩
    133.      *  
    134.      * @param data
    135.      * @return
    136.      * @throws Exception
    137.      */  
    138.     public static byte[] decompress(byte[] data) throws Exception {  
    139.         ByteArrayInputStream bais = new ByteArrayInputStream(data);  
    140.         ByteArrayOutputStream baos = new ByteArrayOutputStream();  
    141.   
    142.         // 解压缩  
    143.   
    144.         decompress(bais, baos);  
    145.   
    146.         data = baos.toByteArray();  
    147.   
    148.         baos.flush();  
    149.         baos.close();  
    150.   
    151.         bais.close();  
    152.   
    153.         return data;  
    154.     }  
    155.   
    156.     /**
    157.      * 文件解压缩
    158.      *  
    159.      * @param file
    160.      * @throws Exception
    161.      */  
    162.     public static void decompress(File file) throws Exception {  
    163.         decompress(file, true);  
    164.     }  
    165.   
    166.     /**
    167.      * 文件解压缩
    168.      *  
    169.      * @param file
    170.      * @param delete
    171.      *            是否删除原始文件
    172.      * @throws Exception
    173.      */  
    174.     public static void decompress(File file, boolean delete) throws Exception {  
    175.         FileInputStream fis = new FileInputStream(file);  
    176.         FileOutputStream fos = new FileOutputStream(file.getPath().replace(EXT,  
    177.                 ""));  
    178.         decompress(fis, fos);  
    179.         fis.close();  
    180.         fos.flush();  
    181.         fos.close();  
    182.   
    183.         if (delete) {  
    184.             file.delete();  
    185.         }  
    186.     }  
    187.   
    188.     /**
    189.      * 数据解压缩
    190.      *  
    191.      * @param is
    192.      * @param os
    193.      * @throws Exception
    194.      */  
    195.     public static void decompress(InputStream is, OutputStream os)  
    196.             throws Exception {  
    197.   
    198.         GZIPInputStream gis = new GZIPInputStream(is);  
    199.   
    200.         int count;  
    201.         byte data[] = new byte[BUFFER];  
    202.         while ((count = gis.read(data, 0, BUFFER)) != -1) {  
    203.             os.write(data, 0, count);  
    204.         }  
    205.   
    206.         gis.close();  
    207.     }  
    208.   
    209.     /**
    210.      * 文件解压缩
    211.      *  
    212.      * @param path
    213.      * @throws Exception
    214.      */  
    215.     public static void decompress(String path) throws Exception {  
    216.         decompress(path, true);  
    217.     }  
    218.   
    219.     /**
    220.      * 文件解压缩
    221.      *  
    222.      * @param path
    223.      * @param delete
    224.      *            是否删除原始文件
    225.      * @throws Exception
    226.      */  
    227.     public static void decompress(String path, boolean delete) throws Exception {  
    228.         File file = new File(path);  
    229.         decompress(file, delete);  
    230.     }  
    231.   
    232. }  
    复制代码
    罗嗦了半天,到底行不行?
    来个测试用例,测试用例如下所示:
    1. /**
    2. * 2010-4-13
    3. */  
    4. package org.zlex.commons.compress.compress;  
    5.   
    6. import static org.junit.Assert.assertEquals;  
    7.   
    8. import java.io.DataInputStream;  
    9. import java.io.File;  
    10. import java.io.FileInputStream;  
    11. import java.io.FileOutputStream;  
    12.   
    13. import org.junit.Test;  
    14.   
    15. /**
    16. * @author <a href="mailto:zlex.dongliang@gmail.com">梁栋</a>
    17. * @since 1.0
    18. */  
    19. public class GZipUtilsTest {  
    20.   
    21.     private String inputStr = "zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org";  
    22.   
    23.     @Test  
    24.     public final void testDataCompress() throws Exception {  
    25.   
    26.         System.err.println("原文:\t" + inputStr);  
    27.   
    28.         byte[] input = inputStr.getBytes();  
    29.         System.err.println("长度:\t" + input.length);  
    30.   
    31.         byte[] data = GZipUtils.compress(input);  
    32.         System.err.println("压缩后:\t");  
    33.         System.err.println("长度:\t" + data.length);  
    34.   
    35.         byte[] output = GZipUtils.decompress(data);  
    36.         String outputStr = new String(output);  
    37.         System.err.println("解压缩后:\t" + outputStr);  
    38.         System.err.println("长度:\t" + output.length);  
    39.   
    40.         assertEquals(inputStr, outputStr);  
    41.   
    42.     }  
    43.   
    44.     @Test  
    45.     public final void testFileCompress() throws Exception {  
    46.   
    47.         FileOutputStream fos = new FileOutputStream("d:/f.txt");  
    48.   
    49.         fos.write(inputStr.getBytes());  
    50.         fos.flush();  
    51.         fos.close();  
    52.   
    53.         GZipUtils.compress("d:/f.txt", false);  
    54.   
    55.         GZipUtils.decompress("d:/f.txt.gz", false);  
    56.   
    57.         File file = new File("d:/f.txt");  
    58.   
    59.         FileInputStream fis = new FileInputStream(file);  
    60.   
    61.         DataInputStream dis = new DataInputStream(fis);  
    62.   
    63.         byte[] data = new byte[(int) file.length()];  
    64.         dis.readFully(data);  
    65.   
    66.         fis.close();  
    67.   
    68.         String outputStr = new String(data);  
    69.         assertEquals(inputStr, outputStr);  
    70.     }  
    71. }  
    复制代码
    结果如何?
    先看testDataCompress()方法控制台输出结果。
    控制台输出如下:
    1. 原文:        zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org
    2. 长度:        52
    3. 压缩后:        
    4. 长度:        45
    5. 解压缩后:        zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org
    6. 长度:        52
    复制代码
    这里使用英文字符做测试,当输入字符串的字节数大于50左右时,压缩效果明显;如果这里使用中文压缩,可能当压缩上千字节时方能体现出压缩效果!
    对于文件操作,朋友们可以自行实验,我代码里的实现是按照gzip命令来的!
    举例来说:
    压缩时,将文件a.txt压缩为a.txt.gz,同时删除文件a.txt。
    解压缩时,将文件a.txt.gz解压缩为a.txt,同时删除文件a.txt.gz。

    注意执行testFileCompress方法,查看产生的文件! 你大可以放到linux上去做验证!

    commons也提供了GZIP算法的实现,甚至更多种压缩算法(tar、bzip2等)的实现,有机会我将继续整理!





    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    守望者AIR技术交流社区(www.airmyth.com)
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2018-4-10 15:18
  • 签到天数: 447 天

    [LV.9]以坛为家II

    1742

    主题

    2094

    帖子

    13万

    积分

    超级版主

    Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18

    威望
    562
    贡献
    29
    金币
    52694
    钢镚
    1422

    开源英雄守望者

    5#
     楼主| 发表于 2015-1-11 13:35:06 | 只看该作者

    Java压缩技术(五) GZIP相关——浏览器解析

    Java压缩技术(五) GZIP相关——浏览器解析

    昨天一篇GZIP相关实现引起大家的广泛关注,为一位朋友验证一下浏览器对gzip的支持情况,才有此文!


    GZIP本身就是一种网络流压缩算法,而且应用相当广泛。如果网络访问过程中,其数据流较大,势必降低网络访问效率,此时就需要考虑使用压缩!当然,在浏览器与服务器的交互中,要考虑浏览器是否支持这些算法,以及服务器运行压缩所带来的负载。如果你关注浏览器上传的“Accept-Encoding”属性,你就能看明白这一点。

    GZIP如何压缩,我这里就不废话了,不清楚的朋友请关注(Java压缩技术(四) GZIP——Java原生实现
    至于如何使得服务器支持gzip的流输出,关键点只有一行代码:
    1. response.setHeader("Content-Encoding", "gzip");  
    复制代码
    经过这项设置,浏览器就能够很好的作出响应!
    先看FireFox,如图:




    再看Opera,如图:




    浏览器在打开该页面时,就可解压获得并展示其内容!
    至于IE就惨了,愣是要求下载! 可能缺少什么设置!(注意后续服务器配置! 不是无解哦!)
    你不信就这么简单?上代码!
    1. /**
    2. * 2010-4-14
    3. */  
    4. import java.io.ByteArrayOutputStream;  
    5. import java.io.IOException;  
    6. import java.io.OutputStream;  
    7. import java.util.zip.GZIPOutputStream;  
    8.   
    9. import javax.servlet.ServletException;  
    10. import javax.servlet.http.HttpServlet;  
    11. import javax.servlet.http.HttpServletRequest;  
    12. import javax.servlet.http.HttpServletResponse;  
    13.   
    14. /**
    15. * GZip服务
    16. *  
    17. * @author <a href="mailto:zlex.dongliang@gmail.com">梁栋</a>
    18. * @since 1.0
    19. */  
    20. public class GZipServlet extends HttpServlet {  
    21.   
    22.     private static final long serialVersionUID = -4811926975427533081L;  
    23.     private static final String ENCODING = "UTF-8";  
    24.   
    25.     /**
    26.      * 压缩
    27.      *  
    28.      * @param data
    29.      * @return
    30.      * @throws Exception
    31.      */  
    32.     private byte[] compress(byte[] data) throws Exception {  
    33.   
    34.         ByteArrayOutputStream baos = new ByteArrayOutputStream();  
    35.   
    36.         // 压缩  
    37.         GZIPOutputStream gos = new GZIPOutputStream(baos);  
    38.   
    39.         gos.write(data, 0, data.length);  
    40.   
    41.         gos.finish();  
    42.   
    43.         byte[] output = baos.toByteArray();  
    44.   
    45.         baos.flush();  
    46.         baos.close();  
    47.   
    48.         return output;  
    49.     }  
    50.   
    51.     /**
    52.      * @param request
    53.      * @param response
    54.      * @throws ServletException
    55.      * @throws IOException
    56.      */  
    57.     private void excute(HttpServletRequest request, HttpServletResponse response)  
    58.             throws ServletException, IOException {  
    59.   
    60.         byte[] data = "我是一个中国人!".getBytes(ENCODING);  
    61.   
    62.         try {  
    63.             byte[] output = compress(data);  
    64.   
    65.             // 设置Content-Encoding,这是关键点!  
    66.             response.setHeader("Content-Encoding", "gzip");  
    67.             // 设置字符集  
    68.             response.setCharacterEncoding(ENCODING);  
    69.             // 设定输出流中内容长度  
    70.             response.setContentLength(output.length);  
    71.   
    72.             OutputStream out = response.getOutputStream();  
    73.             out.write(output);  
    74.             out.flush();  
    75.             out.close();  
    76.         } catch (Exception e) {  
    77.             e.printStackTrace();  
    78.         }  
    79.     }  
    80.   
    81.     /**
    82.      * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
    83.      *      response)
    84.      */  
    85.     protected void doGet(HttpServletRequest request,  
    86.             HttpServletResponse response) throws ServletException, IOException {  
    87.         excute(request, response);  
    88.     }  
    89.   
    90.     /**
    91.      * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
    92.      *      response)
    93.      */  
    94.     protected void doPost(HttpServletRequest request,  
    95.             HttpServletResponse response) throws ServletException, IOException {  
    96.         excute(request, response);  
    97.     }  
    98.   
    99. }  
    复制代码
    其实,就这些内容!

    当然,除了上述代码方式,针对于tomcat可以通过修改配置获得支持!
    1. <Connector   
    2.               port="8080"   
    3.               protocol="HTTP/1.1"  
    4.               connectionTimeout="20000"  
    5.               redirectPort="443"   
    6.               URIEncoding="UTF-8"  
    7.               compression="on"     
    8.               noCompressionUserAgents="gozilla, traviata"     
    9.               compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain,application/json"   
    10. />   
    复制代码
    说说配置细节:
    compression="on"   开启压缩支持
    noCompressionUserAgents="gozilla, traviata"   不压缩的内容
    compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain,application/json" 压缩的类型

    至于代码,你无需写一行代码!轻松获得服务器访问加速! 并且IE也支持哦!

    借网友经验,如下实现,轻松获得IE支持:
    1. response.setContentType("text/plain;charset=utf-8");   
    复制代码
    工程在我的附件里,请下载验证!



    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    守望者AIR技术交流社区(www.airmyth.com)
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2018-4-10 15:18
  • 签到天数: 447 天

    [LV.9]以坛为家II

    1742

    主题

    2094

    帖子

    13万

    积分

    超级版主

    Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18

    威望
    562
    贡献
    29
    金币
    52694
    钢镚
    1422

    开源英雄守望者

    6#
     楼主| 发表于 2015-1-11 13:39:02 | 只看该作者

    Java压缩技术(六) BZIP2——Commons实现

    Java压缩技术(六) BZIP2——Commons实现



    想要把一整套算法都整理出来,的确是件非常老心费力的事情! 但是如果一件事情不能有始有终,难免会有遗憾! 索性,继续整理!



    BZip2与GZip有什么渊源,我这里不深究。我要说的只是,这两种算法,你在linux下都可以找到相应的操作命令。

    GZip
    压缩
    gzip <file> 将得到压缩文件<file>.gz,同时删除文件<file>
    解压缩
    gzip -d <file>.gz 将得到压缩文件<file>,同时删除文件<file>.gz

    BZip2与之相当,几乎没有什么差别~~
    BZip2
    压缩
    bzip2 <file> 将得到压缩文件<file>.bz2,同时删除文件<file>
    解压缩
    bzip2 -d <file>.bz2 将得到压缩文件<file>,同时删除文件<file>.bz2

    除了命令不同外,几乎是一样的!

    再说实现。GZIP是JDK自带的算法实现,但BZip2则不曾享受这个待遇。 不过,强大的Apache坚决不会让这些个在Linux下如鱼得水的算法在Java世界中销声匿迹。Apache在Commons Compress中提供了相应的实现。同时,还包括众所周知的tar、cpio、zip等算法实现,其中最为丰富的当属zip实现了!

    我继续依葫芦画瓢~~~
    BZip2CompressorOutputStream类用于压缩
    BZip2CompressorInputStream类用于解压缩

    先说压缩实现,BZip2CompressorOutputStream只有一个方法用于压缩,就是带定长的write方法。简单调用如下文所示:
    1. /**
    2. * 数据压缩
    3. *  
    4. * @param is
    5. * @param os
    6. * @throws Exception
    7. */  
    8. public static void compress(InputStream is, OutputStream os)  
    9.         throws Exception {  
    10.   
    11.     BZip2CompressorOutputStream gos = new BZip2CompressorOutputStream(os);  
    12.   
    13.     int count;  
    14.     byte data[] = new byte[BUFFER];  
    15.     while ((count = is.read(data, 0, BUFFER)) != -1) {  
    16.         gos.write(data, 0, count);  
    17.     }  
    18.   
    19.     gos.finish();  
    20.   
    21.     gos.flush();  
    22.     gos.close();  
    23. }  
    复制代码
    与GZip实现有何差别?除了换掉了GZIPOutputStream没有任何差别。

    解压缩就更不用说了,BZip2CompressorInputStream提供了一个带定长的read方法。简单调用如下文所示:
    1. /**
    2. * 数据解压缩
    3. *  
    4. * @param is
    5. * @param os
    6. * @throws Exception
    7. */  
    8. public static void decompress(InputStream is, OutputStream os)  
    9.         throws Exception {  
    10.   
    11.     BZip2CompressorInputStream gis = new BZip2CompressorInputStream(is);  
    12.   
    13.     int count;  
    14.     byte data[] = new byte[BUFFER];  
    15.     while ((count = gis.read(data, 0, BUFFER)) != -1) {  
    16.         os.write(data, 0, count);  
    17.     }  
    18.   
    19.     gis.close();  
    20. }  
    复制代码
    嗯,没什么难度!
    IT这行就是这样,只要你肯用心,能触类旁通,就能融会贯通!
    给一个完整实现:
    1. /**
    2. * 2010-4-15
    3. */  
    4. package org.zlex.commons.compress.compress;  
    5.   
    6. import java.io.ByteArrayInputStream;  
    7. import java.io.ByteArrayOutputStream;  
    8. import java.io.File;  
    9. import java.io.FileInputStream;  
    10. import java.io.FileOutputStream;  
    11. import java.io.InputStream;  
    12. import java.io.OutputStream;  
    13.   
    14. import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;  
    15. import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream;  
    16.   
    17. /**
    18. * BZip2工具
    19. *  
    20. * @author  <a href="mailto:zlex.dongliang@gmail.com">梁栋</a>
    21. * @since 1.0
    22. */  
    23. public abstract class BZip2Utils {  
    24.   
    25.     public static final int BUFFER = 1024;  
    26.     public static final CharSequence EXT = ".bz2";  
    27.   
    28.     /**
    29.      * 数据压缩
    30.      *  
    31.      * @param data
    32.      * @return
    33.      * @throws Exception
    34.      */  
    35.     public static byte[] compress(byte[] data) throws Exception {  
    36.         ByteArrayInputStream bais = new ByteArrayInputStream(data);  
    37.         ByteArrayOutputStream baos = new ByteArrayOutputStream();  
    38.   
    39.         // 压缩  
    40.         compress(bais, baos);  
    41.   
    42.         byte[] output = baos.toByteArray();  
    43.   
    44.         baos.flush();  
    45.         baos.close();  
    46.   
    47.         bais.close();  
    48.   
    49.         return output;  
    50.     }  
    51.   
    52.     /**
    53.      * 文件压缩
    54.      *  
    55.      * @param file
    56.      * @throws Exception
    57.      */  
    58.     public static void compress(File file) throws Exception {  
    59.         compress(file, true);  
    60.     }  
    61.   
    62.     /**
    63.      * 文件压缩
    64.      *  
    65.      * @param file
    66.      * @param delete
    67.      *            是否删除原始文件
    68.      * @throws Exception
    69.      */  
    70.     public static void compress(File file, boolean delete) throws Exception {  
    71.         FileInputStream fis = new FileInputStream(file);  
    72.         FileOutputStream fos = new FileOutputStream(file.getPath() + EXT);  
    73.   
    74.         compress(fis, fos);  
    75.   
    76.         fis.close();  
    77.         fos.flush();  
    78.         fos.close();  
    79.   
    80.         if (delete) {  
    81.             file.delete();  
    82.         }  
    83.     }  
    84.   
    85.     /**
    86.      * 数据压缩
    87.      *  
    88.      * @param is
    89.      * @param os
    90.      * @throws Exception
    91.      */  
    92.     public static void compress(InputStream is, OutputStream os)  
    93.             throws Exception {  
    94.   
    95.         BZip2CompressorOutputStream gos = new BZip2CompressorOutputStream(os);  
    96.   
    97.         int count;  
    98.         byte data[] = new byte[BUFFER];  
    99.         while ((count = is.read(data, 0, BUFFER)) != -1) {  
    100.             gos.write(data, 0, count);  
    101.         }  
    102.   
    103.         gos.finish();  
    104.   
    105.         gos.flush();  
    106.         gos.close();  
    107.     }  
    108.   
    109.     /**
    110.      * 文件压缩
    111.      *  
    112.      * @param path
    113.      * @throws Exception
    114.      */  
    115.     public static void compress(String path) throws Exception {  
    116.         compress(path, true);  
    117.     }  
    118.   
    119.     /**
    120.      * 文件压缩
    121.      *  
    122.      * @param path
    123.      * @param delete
    124.      *            是否删除原始文件
    125.      * @throws Exception
    126.      */  
    127.     public static void compress(String path, boolean delete) throws Exception {  
    128.         File file = new File(path);  
    129.         compress(file, delete);  
    130.     }  
    131.   
    132.     /**
    133.      * 数据解压缩
    134.      *  
    135.      * @param data
    136.      * @return
    137.      * @throws Exception
    138.      */  
    139.     public static byte[] decompress(byte[] data) throws Exception {  
    140.         ByteArrayInputStream bais = new ByteArrayInputStream(data);  
    141.         ByteArrayOutputStream baos = new ByteArrayOutputStream();  
    142.   
    143.         // 解压缩  
    144.   
    145.         decompress(bais, baos);  
    146.   
    147.         data = baos.toByteArray();  
    148.   
    149.         baos.flush();  
    150.         baos.close();  
    151.   
    152.         bais.close();  
    153.   
    154.         return data;  
    155.     }  
    156.   
    157.     /**
    158.      * 文件解压缩
    159.      *  
    160.      * @param file
    161.      * @throws Exception
    162.      */  
    163.     public static void decompress(File file) throws Exception {  
    164.         decompress(file, true);  
    165.     }  
    166.   
    167.     /**
    168.      * 文件解压缩
    169.      *  
    170.      * @param file
    171.      * @param delete
    172.      *            是否删除原始文件
    173.      * @throws Exception
    174.      */  
    175.     public static void decompress(File file, boolean delete) throws Exception {  
    176.         FileInputStream fis = new FileInputStream(file);  
    177.         FileOutputStream fos = new FileOutputStream(file.getPath().replace(EXT,  
    178.                 ""));  
    179.         decompress(fis, fos);  
    180.         fis.close();  
    181.         fos.flush();  
    182.         fos.close();  
    183.   
    184.         if (delete) {  
    185.             file.delete();  
    186.         }  
    187.     }  
    188.   
    189.     /**
    190.      * 数据解压缩
    191.      *  
    192.      * @param is
    193.      * @param os
    194.      * @throws Exception
    195.      */  
    196.     public static void decompress(InputStream is, OutputStream os)  
    197.             throws Exception {  
    198.   
    199.         BZip2CompressorInputStream gis = new BZip2CompressorInputStream(is);  
    200.   
    201.         int count;  
    202.         byte data[] = new byte[BUFFER];  
    203.         while ((count = gis.read(data, 0, BUFFER)) != -1) {  
    204.             os.write(data, 0, count);  
    205.         }  
    206.   
    207.         gis.close();  
    208.     }  
    209.   
    210.     /**
    211.      * 文件解压缩
    212.      *  
    213.      * @param path
    214.      * @throws Exception
    215.      */  
    216.     public static void decompress(String path) throws Exception {  
    217.         decompress(path, true);  
    218.     }  
    219.   
    220.     /**
    221.      * 文件解压缩
    222.      *  
    223.      * @param path
    224.      * @param delete
    225.      *            是否删除原始文件
    226.      * @throws Exception
    227.      */  
    228.     public static void decompress(String path, boolean delete) throws Exception {  
    229.         File file = new File(path);  
    230.         decompress(file, delete);  
    231.     }  
    232.   
    233. }  
    复制代码
    对应再来个测试用例,测试用例如下所示:
    1. /**
    2. * 2010-4-13
    3. */  
    4. package org.zlex.commons.compress.compress;  
    5.   
    6. import static org.junit.Assert.assertEquals;  
    7.   
    8. import java.io.DataInputStream;  
    9. import java.io.File;  
    10. import java.io.FileInputStream;  
    11. import java.io.FileOutputStream;  
    12.   
    13. import org.junit.Test;  
    14.   
    15. /**
    16. * BZip2
    17. *  
    18. * @author <a href="mailto:zlex.dongliang@gmail.com">梁栋</a>
    19. * @since 1.0
    20. */  
    21. public class BZip2UtilsTest {  
    22.   
    23.     private String inputStr = "zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org,zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org,zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org,zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org,zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org,zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org,zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org,zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org,zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org,zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org";  
    24.   
    25.     @Test  
    26.     public final void testDataCompress() throws Exception {  
    27.   
    28.         byte[] input = inputStr.getBytes();  
    29.         System.err.println("原文:\t" + inputStr);  
    30.         System.err.println("长度:\t" + input.length);  
    31.   
    32.         byte[] data = BZip2Utils.compress(input);  
    33.         System.err.println("压缩后:\t");  
    34.         System.err.println("长度:\t" + data.length);  
    35.   
    36.         byte[] output = BZip2Utils.decompress(data);  
    37.         String outputStr = new String(output);  
    38.         System.err.println("解压缩后:\t" + outputStr);  
    39.         System.err.println("长度:\t" + output.length);  
    40.   
    41.         assertEquals(inputStr, outputStr);  
    42.   
    43.     }  
    44.   
    45.     @Test  
    46.     public final void testFileCompress() throws Exception {  
    47.   
    48.         FileOutputStream fos = new FileOutputStream("d:/f.txt");  
    49.   
    50.         fos.write(inputStr.getBytes());  
    51.         fos.flush();  
    52.         fos.close();  
    53.   
    54.         BZip2Utils.compress("d:/f.txt");  
    55.   
    56.         BZip2Utils.decompress("d:/f.txt.bz2");  
    57.   
    58.         File file = new File("d:/f.txt");  
    59.   
    60.         FileInputStream fis = new FileInputStream(file);  
    61.   
    62.         DataInputStream dis = new DataInputStream(fis);  
    63.   
    64.         byte[] data = new byte[(int) file.length()];  
    65.         dis.readFully(data);  
    66.   
    67.         fis.close();  
    68.   
    69.         String outputStr = new String(data);  
    70.         assertEquals(inputStr, outputStr);  
    71.     }  
    72. }  
    复制代码
    虽然,两种算法在代码实现上几乎没有什么差别,但在压缩上想要看到效果,还真让我费了点事!
    控制台输出如下所示:
    1. 原文: zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org,zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org,zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org,zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org,zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org,zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org,zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org,zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org,zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org,zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org
    2. 长度:        529
    3. 压缩后:        
    4. 长度:        76
    5. 解压缩后: zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org,zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org,zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org,zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org,zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org,zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org,zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org,zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org,zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org,zlex@zlex.org,snowolf@zlex.org,zlex.snowolf@zlex.org
    6. 长度:        529
    复制代码
    529字节-->76字节!
    GZIP本身不需要太长的内容,经过压缩就能体现出压缩效果,而BZip2则需要压缩很长的内容时,才能体现其压缩效果,这说明BZip2更适合大数据压缩?!

    Commons Compress不仅支持BZip2算法实现,同时也支持GZip算法实现。对于GZip算法实现,与Java原生实现基本上没有什么差别。其源代码分析,仅仅是做了简单的包装。
    不过有必要提及的一点是,Commons Compress为压缩(GZip和BZip2)构建了压缩算法工厂类CompressorStreamFactory。通过这个类可以方便的构建GZip和BZip2的输入输出流,关键字分别为“gz”和“bzip2”。

    GZip
    1. // GzipCompressorInputStream        
    2. CompressorInputStream gzipIn = new CompressorStreamFactory()  
    3.         .createCompressorInputStream("gz", is);  
    4.   
    5. // GzipCompressorOutputStream  
    6. CompressorOutputStream gzipOut = new CompressorStreamFactory()  
    7.         .createCompressorOutputStream("gz", os);  
    复制代码
    BZip2
    1. // BZip2CompressorInputStream  
    2. CompressorInputStream bzip2In = new CompressorStreamFactory()  
    3.         .createCompressorInputStream("bzip2", is);  
    4.   
    5. // BZip2CompressorOutputStream  
    6. CompressorOutputStream bzip2Out = new CompressorStreamFactory()  
    7.         .createCompressorOutputStream("bzip2", os);  
    复制代码
    GZip和BZip2在算法实现步骤上基本上没有什么差别,如果有必要统一,可按上述代码实现!


    完整代码详见附件!





    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    守望者AIR技术交流社区(www.airmyth.com)
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2018-4-10 15:18
  • 签到天数: 447 天

    [LV.9]以坛为家II

    1742

    主题

    2094

    帖子

    13万

    积分

    超级版主

    Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18

    威望
    562
    贡献
    29
    金币
    52694
    钢镚
    1422

    开源英雄守望者

    7#
     楼主| 发表于 2015-1-11 13:46:42 | 只看该作者
    Java压缩技术(七) TAR——Commons实现

    在linux下,tar是一个归档命令。当然,如果配合gzip、bzip2就可以达到归档+压缩的效果!
    我们通过tar获得归档压缩文件其实恰恰包含了归档压缩两个操作,并且其操作次序也是先做归档操作,再做压缩操作! 通常我们忽略了归档的概念,将归档压缩文件简称为压缩文件!~


    顺便复习一遍linux命令:
    tar cf <file.tar> <file>将由文件<file>创建名为<file.tar>归档文件,同时保留原文件。
    tar xf <file.tar>将由归档文件<file.tar>创建名为<file>的文件/目录,同时保留原文件。

    对于归档压缩,需分为gzip和bzip2,相应的linux为:
    gzip
    tar czf <file.tar.gz> <file>将由文件<file>创建名为<file.tar.gz>归档压缩文件,同时保留原文件。
    tar xzf <file.tar.gz>将由归档压缩文件<file.tar.gz>创建名为<file>的文件/目录,同时保留原文件。

    bzip2
    tar cjf <file.tar.bz2> <file>将由文件<file>创建名为<file.tar.bz2>归档压缩文件,同时保留原文件。
    tar xjf <file.tar.bz2>将由归档压缩文件<file.tar.bz2>创建名为<file>的文件/目录,同时保留原文件。

    今天的主角是Apache Commons Compress下用于Tar操作的三元干将
    TarArchiveEntry 类似于Java 原生的ZipEntry,可以理解为Tar归档添加项。
    TarArchiveOutputStream Tar归档输出流,用于归档。
    TarArchiveInputStream Tar归档输入流,用于解归档。

    至于jar,其实现方式与tar非常接近,我就不在这里废话了!
    JarArchiveEntry 类似于Java 原生的ZipEntry,可以理解为Jar归档添加项。
    JarArchiveOutputStream Jar归档输出流,用于归档。
    JarArchiveInputStream Jar归档输入流,用于解归档。

    读过Java压缩技术(二)Java压缩技术(三)会发现,其实Tar的实现与Java原生的Zip实现方式基本上没有差别!
    先说归档,依旧需要考虑待归档的对象是文件还是目录:
    1. /**
    2. * 归档
    3. *  
    4. * @param srcFile
    5. *            源路径
    6. * @param taos
    7. *            TarArchiveOutputStream
    8. * @param basePath
    9. *            归档包内相对路径
    10. * @throws Exception
    11. */  
    12. private static void archive(File srcFile, TarArchiveOutputStream taos,  
    13.         String basePath) throws Exception {  
    14.     if (srcFile.isDirectory()) {  
    15.         archiveDir(srcFile, taos, basePath);  
    16.     } else {  
    17.         archiveFile(srcFile, taos, basePath);  
    18.     }  
    19. }  
    复制代码
    对于目录,需要区分空目录和包含文件的目录。
    如果是空目录,只要简单追加一个归档项(TarArchiveEntry)即可,但注意其名字的结尾需要使用"/"作为区分目录的标识符(String PATH = "/";)。
    如果是带有子文件的目录,则需要对其迭代归档:
    1. /**
    2. * 目录归档
    3. *  
    4. * @param dir
    5. * @param taos
    6. *            TarArchiveOutputStream
    7. * @param basePath
    8. * @throws Exception
    9. */  
    10. private static void archiveDir(File dir, TarArchiveOutputStream taos,  
    11.         String basePath) throws Exception {  
    12.   
    13.     File[] files = dir.listFiles();  
    14.   
    15.     if (files.length < 1) {  
    16.         TarArchiveEntry entry = new TarArchiveEntry(basePath  
    17.                 + dir.getName() + PATH);  
    18.   
    19.         taos.putArchiveEntry(entry);  
    20.         taos.closeArchiveEntry();  
    21.     }  
    22.   
    23.     for (File file : files) {  
    24.   
    25.         // 递归归档  
    26.         archive(file, taos, basePath + dir.getName() + PATH);  
    27.   
    28.     }  
    29. }  
    复制代码
    最后,来看归档操作:
    1. /**
    2. * 数据归档
    3. *  
    4. * @param data
    5. *            待归档数据
    6. * @param path
    7. *            归档数据的当前路径
    8. * @param name
    9. *            归档文件名
    10. * @param taos
    11. *            TarArchiveOutputStream
    12. * @throws Exception
    13. */  
    14. private static void archiveFile(File file, TarArchiveOutputStream taos,  
    15.         String dir) throws Exception {  
    16.   
    17.     TarArchiveEntry entry = new TarArchiveEntry(dir + file.getName());  
    18.   
    19.     entry.setSize(file.length());  
    20.   
    21.     taos.putArchiveEntry(entry);  
    22.   
    23.     BufferedInputStream bis = new BufferedInputStream(new FileInputStream(  
    24.             file));  
    25.     int count;  
    26.     byte data[] = new byte[BUFFER];  
    27.     while ((count = bis.read(data, 0, BUFFER)) != -1) {  
    28.         taos.write(data, 0, count);  
    29.     }  
    30.   
    31.     bis.close();  
    32.   
    33.     taos.closeArchiveEntry();  
    34. }  
    复制代码
    注意执行归档操作后,执行closeArchiveEntry()方法。
    Tar解归档,与Zip解压相似,一样要遍历获得归档项:
    1. /**
    2. * 文件 解归档
    3. *  
    4. * @param destFile
    5. *            目标文件
    6. * @param tais
    7. *            ZipInputStream
    8. * @throws Exception
    9. */  
    10. private static void dearchive(File destFile, TarArchiveInputStream tais)  
    11.         throws Exception {  
    12.   
    13.     TarArchiveEntry entry = null;  
    14.     while ((entry = tais.getNextTarEntry()) != 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.             dearchiveFile(dirFile, tais);  
    28.         }  
    29.   
    30.     }  
    31. }  
    复制代码
    最后,进行解归档:
    1. /**
    2. * 文件解归档
    3. *  
    4. * @param destFile
    5. *            目标文件
    6. * @param tais
    7. *            TarArchiveInputStream
    8. * @throws Exception
    9. */  
    10. private static void dearchiveFile(File destFile, TarArchiveInputStream tais)  
    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 = tais.read(data, 0, BUFFER)) != -1) {  
    19.         bos.write(data, 0, count);  
    20.     }  
    21.   
    22.     bos.close();  
    23. }  
    复制代码
    文件探针用于构建父目录:
    1. /**
    2. * 文件探针
    3. *  
    4. * <pre>
    5. * 当父目录不存在时,创建目录!
    6. * </pre>
    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. }  
    复制代码
    给出完整实现:
    1. /**
    2. * 2010-4-20
    3. */  
    4. package org.zlex.commons.compress;  
    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.   
    12. import org.apache.commons.compress.archivers.tar.TarArchiveEntry;  
    13. import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;  
    14. import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;  
    15.   
    16. /**
    17. * TAR工具
    18. *  
    19. * @author <a href="mailto:zlex.dongliang@gmail.com">梁栋</a>
    20. * @since 1.0
    21. */  
    22. public abstract class TarUtils {  
    23.   
    24.     private static final String BASE_DIR = "";  
    25.   
    26.     // 符号"/"用来作为目录标识判断符  
    27.     private static final String PATH = "/";  
    28.     private static final int BUFFER = 1024;  
    29.   
    30.     private static final String EXT = ".tar";  
    31.   
    32.     /**
    33.      * 归档
    34.      *  
    35.      * @param srcPath
    36.      * @param destPath
    37.      * @throws Exception
    38.      */  
    39.     public static void archive(String srcPath, String destPath)  
    40.             throws Exception {  
    41.   
    42.         File srcFile = new File(srcPath);  
    43.   
    44.         archive(srcFile, destPath);  
    45.   
    46.     }  
    47.   
    48.     /**
    49.      * 归档
    50.      *  
    51.      * @param srcFile
    52.      *            源路径
    53.      * @param destPath
    54.      *            目标路径
    55.      * @throws Exception
    56.      */  
    57.     public static void archive(File srcFile, File destFile) throws Exception {  
    58.   
    59.         TarArchiveOutputStream taos = new TarArchiveOutputStream(  
    60.                 new FileOutputStream(destFile));  
    61.   
    62.         archive(srcFile, taos, BASE_DIR);  
    63.   
    64.         taos.flush();  
    65.         taos.close();  
    66.     }  
    67.   
    68.     /**
    69.      * 归档
    70.      *  
    71.      * @param srcFile
    72.      * @throws Exception
    73.      */  
    74.     public static void archive(File srcFile) throws Exception {  
    75.         String name = srcFile.getName();  
    76.         String basePath = srcFile.getParent();  
    77.         String destPath = basePath + name + EXT;  
    78.         archive(srcFile, destPath);  
    79.     }  
    80.   
    81.     /**
    82.      * 归档文件
    83.      *  
    84.      * @param srcFile
    85.      * @param destPath
    86.      * @throws Exception
    87.      */  
    88.     public static void archive(File srcFile, String destPath) throws Exception {  
    89.         archive(srcFile, new File(destPath));  
    90.     }  
    91.   
    92.     /**
    93.      * 归档
    94.      *  
    95.      * @param srcPath
    96.      * @throws Exception
    97.      */  
    98.     public static void archive(String srcPath) throws Exception {  
    99.         File srcFile = new File(srcPath);  
    100.   
    101.         archive(srcFile);  
    102.     }  
    103.   
    104.     /**
    105.      * 归档
    106.      *  
    107.      * @param srcFile
    108.      *            源路径
    109.      * @param taos
    110.      *            TarArchiveOutputStream
    111.      * @param basePath
    112.      *            归档包内相对路径
    113.      * @throws Exception
    114.      */  
    115.     private static void archive(File srcFile, TarArchiveOutputStream taos,  
    116.             String basePath) throws Exception {  
    117.         if (srcFile.isDirectory()) {  
    118.             archiveDir(srcFile, taos, basePath);  
    119.         } else {  
    120.             archiveFile(srcFile, taos, basePath);  
    121.         }  
    122.     }  
    123.   
    124.     /**
    125.      * 目录归档
    126.      *  
    127.      * @param dir
    128.      * @param taos
    129.      *            TarArchiveOutputStream
    130.      * @param basePath
    131.      * @throws Exception
    132.      */  
    133.     private static void archiveDir(File dir, TarArchiveOutputStream taos,  
    134.             String basePath) throws Exception {  
    135.   
    136.         File[] files = dir.listFiles();  
    137.   
    138.         if (files.length < 1) {  
    139.             TarArchiveEntry entry = new TarArchiveEntry(basePath  
    140.                     + dir.getName() + PATH);  
    141.   
    142.             taos.putArchiveEntry(entry);  
    143.             taos.closeArchiveEntry();  
    144.         }  
    145.   
    146.         for (File file : files) {  
    147.   
    148.             // 递归归档  
    149.             archive(file, taos, basePath + dir.getName() + PATH);  
    150.   
    151.         }  
    152.     }  
    153.   
    154.     /**
    155.      * 数据归档
    156.      *  
    157.      * @param data
    158.      *            待归档数据
    159.      * @param path
    160.      *            归档数据的当前路径
    161.      * @param name
    162.      *            归档文件名
    163.      * @param taos
    164.      *            TarArchiveOutputStream
    165.      * @throws Exception
    166.      */  
    167.     private static void archiveFile(File file, TarArchiveOutputStream taos,  
    168.             String dir) throws Exception {  
    169.   
    170.         /**
    171.          * 归档内文件名定义
    172.          *  
    173.          * <pre>
    174.          * 如果有多级目录,那么这里就需要给出包含目录的文件名
    175.          * 如果用WinRAR打开归档包,中文名将显示为乱码
    176.          * </pre>
    177.          */  
    178.         TarArchiveEntry entry = new TarArchiveEntry(dir + file.getName());  
    179.   
    180.         entry.setSize(file.length());  
    181.   
    182.         taos.putArchiveEntry(entry);  
    183.   
    184.         BufferedInputStream bis = new BufferedInputStream(new FileInputStream(  
    185.                 file));  
    186.         int count;  
    187.         byte data[] = new byte[BUFFER];  
    188.         while ((count = bis.read(data, 0, BUFFER)) != -1) {  
    189.             taos.write(data, 0, count);  
    190.         }  
    191.   
    192.         bis.close();  
    193.   
    194.         taos.closeArchiveEntry();  
    195.     }  
    196.   
    197.     /**
    198.      * 解归档
    199.      *  
    200.      * @param srcFile
    201.      * @throws Exception
    202.      */  
    203.     public static void dearchive(File srcFile) throws Exception {  
    204.         String basePath = srcFile.getParent();  
    205.         dearchive(srcFile, basePath);  
    206.     }  
    207.   
    208.     /**
    209.      * 解归档
    210.      *  
    211.      * @param srcFile
    212.      * @param destFile
    213.      * @throws Exception
    214.      */  
    215.     public static void dearchive(File srcFile, File destFile) throws Exception {  
    216.   
    217.         TarArchiveInputStream tais = new TarArchiveInputStream(  
    218.                 new FileInputStream(srcFile));  
    219.         dearchive(destFile, tais);  
    220.   
    221.         tais.close();  
    222.   
    223.     }  
    224.   
    225.     /**
    226.      * 解归档
    227.      *  
    228.      * @param srcFile
    229.      * @param destPath
    230.      * @throws Exception
    231.      */  
    232.     public static void dearchive(File srcFile, String destPath)  
    233.             throws Exception {  
    234.         dearchive(srcFile, new File(destPath));  
    235.   
    236.     }  
    237.   
    238.     /**
    239.      * 文件 解归档
    240.      *  
    241.      * @param destFile
    242.      *            目标文件
    243.      * @param tais
    244.      *            ZipInputStream
    245.      * @throws Exception
    246.      */  
    247.     private static void dearchive(File destFile, TarArchiveInputStream tais)  
    248.             throws Exception {  
    249.   
    250.         TarArchiveEntry entry = null;  
    251.         while ((entry = tais.getNextTarEntry()) != null) {  
    252.   
    253.             // 文件  
    254.             String dir = destFile.getPath() + File.separator + entry.getName();  
    255.   
    256.             File dirFile = new File(dir);  
    257.   
    258.             // 文件检查  
    259.             fileProber(dirFile);  
    260.   
    261.             if (entry.isDirectory()) {  
    262.                 dirFile.mkdirs();  
    263.             } else {  
    264.                 dearchiveFile(dirFile, tais);  
    265.             }  
    266.   
    267.         }  
    268.     }  
    269.   
    270.     /**
    271.      * 文件 解归档
    272.      *  
    273.      * @param srcPath
    274.      *            源文件路径
    275.      *  
    276.      * @throws Exception
    277.      */  
    278.     public static void dearchive(String srcPath) throws Exception {  
    279.         File srcFile = new File(srcPath);  
    280.   
    281.         dearchive(srcFile);  
    282.     }  
    283.   
    284.     /**
    285.      * 文件 解归档
    286.      *  
    287.      * @param srcPath
    288.      *            源文件路径
    289.      * @param destPath
    290.      *            目标文件路径
    291.      * @throws Exception
    292.      */  
    293.     public static void dearchive(String srcPath, String destPath)  
    294.             throws Exception {  
    295.   
    296.         File srcFile = new File(srcPath);  
    297.         dearchive(srcFile, destPath);  
    298.     }  
    299.   
    300.     /**
    301.      * 文件解归档
    302.      *  
    303.      * @param destFile
    304.      *            目标文件
    305.      * @param tais
    306.      *            TarArchiveInputStream
    307.      * @throws Exception
    308.      */  
    309.     private static void dearchiveFile(File destFile, TarArchiveInputStream tais)  
    310.             throws Exception {  
    311.   
    312.         BufferedOutputStream bos = new BufferedOutputStream(  
    313.                 new FileOutputStream(destFile));  
    314.   
    315.         int count;  
    316.         byte data[] = new byte[BUFFER];  
    317.         while ((count = tais.read(data, 0, BUFFER)) != -1) {  
    318.             bos.write(data, 0, count);  
    319.         }  
    320.   
    321.         bos.close();  
    322.     }  
    323.   
    324.     /**
    325.      * 文件探针
    326.      *  
    327.      * <pre>
    328.      * 当父目录不存在时,创建目录!
    329.      * </pre>
    330.      *  
    331.      * @param dirFile
    332.      */  
    333.     private static void fileProber(File dirFile) {  
    334.   
    335.         File parentFile = dirFile.getParentFile();  
    336.         if (!parentFile.exists()) {  
    337.   
    338.             // 递归寻找上级目录  
    339.             fileProber(parentFile);  
    340.   
    341.             parentFile.mkdir();  
    342.         }  
    343.   
    344.     }  
    345.   
    346. }  
    复制代码
    最后给出测试用例:
    1. /**
    2. * 2010-4-20
    3. */  
    4. package org.zlex.commons.compress;  
    5.   
    6. import static org.junit.Assert.*;  
    7.   
    8. import java.io.DataInputStream;  
    9. import java.io.File;  
    10. import java.io.FileInputStream;  
    11. import java.io.FileOutputStream;  
    12.   
    13. import org.junit.Before;  
    14. import org.junit.Test;  
    15.   
    16. /**
    17. * Tar测试
    18. *  
    19. * @author <a href="mailto:zlex.dongliang@gmail.com">梁栋</a>
    20. * @since 1.0
    21. */  
    22. public class TarUtilsTest {  
    23.     private String inputStr;  
    24.     private String name = "data.xml";  
    25.   
    26.     @Before  
    27.     public void before() {  
    28.         StringBuilder sb = new StringBuilder();  
    29.         sb.append("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");  
    30.         sb.append("\r\n");  
    31.         sb.append("<dataGroup>");  
    32.         sb.append("\r\n\t");  
    33.         sb.append("<dataItem>");  
    34.         sb.append("\r\n\t\t");  
    35.         sb.append("<data>");  
    36.         sb.append("Test");  
    37.         sb.append("</data>");  
    38.         sb.append("\r\n\t");  
    39.         sb.append("<dataItem>");  
    40.         sb.append("\r\n");  
    41.         sb.append("</dataGroup>");  
    42.   
    43.         inputStr = sb.toString();  
    44.     }  
    45.   
    46.     @Test  
    47.     public void testArchiveFile() throws Exception {  
    48.   
    49.         byte[] contentOfEntry = inputStr.getBytes();  
    50.   
    51.         String path = "d:/" + name;  
    52.   
    53.         FileOutputStream fos = new FileOutputStream(path);  
    54.   
    55.         fos.write(contentOfEntry);  
    56.         fos.flush();  
    57.         fos.close();  
    58.   
    59.         TarUtils.archive(path);  
    60.   
    61.         TarUtils.dearchive(path + ".tar");  
    62.   
    63.         File file = new File(path);  
    64.   
    65.         FileInputStream fis = new FileInputStream(file);  
    66.   
    67.         DataInputStream dis = new DataInputStream(fis);  
    68.   
    69.         byte[] data = new byte[(int) file.length()];  
    70.   
    71.         dis.readFully(data);  
    72.   
    73.         fis.close();  
    74.   
    75.         String outputStr = new String(data);  
    76.         assertEquals(inputStr, outputStr);  
    77.   
    78.     }  
    79.   
    80.     @Test  
    81.     public void testArchiveDir() throws Exception {  
    82.         String path = "d:/fd";  
    83.         TarUtils.archive(path);  
    84.   
    85.         TarUtils.dearchive(path + ".tar", "d:/fds");  
    86.     }  
    87.   
    88. }  
    复制代码
    执行代码,来看下效果:




    这是原始文件。




    这是归档后的文件。
    注意红框,这里没有经过任何压缩!
    除了tar、zip,其实还有很多归档算法,如ar、jar、cpio。其实现方式,与上述内容较为接近。
    至于压缩成*.tar.gz、*.tar.bz2,请朋友们参照前几篇内容!

    完整实现见附件!





    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    守望者AIR技术交流社区(www.airmyth.com)
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    慵懒
    2016-8-19 16:03
  • 签到天数: 3 天

    [LV.2]偶尔看看I

    1

    主题

    4

    帖子

    4259

    积分

    中尉

    Rank: 7Rank: 7Rank: 7

    威望
    0
    贡献
    16
    金币
    117
    钢镚
    10
    8#
    发表于 2015-1-11 17:10:44 | 只看该作者
    顶........
    守望者AIR技术交流社区(www.airmyth.com)
    回复

    使用道具 举报

  • TA的每日心情
    郁闷
    2016-8-19 16:08
  • 签到天数: 7 天

    [LV.3]偶尔看看II

    4

    主题

    31

    帖子

    2628

    积分

    少尉

    Rank: 6Rank: 6

    威望
    0
    贡献
    8
    金币
    320
    钢镚
    25
    9#
    发表于 2016-8-17 16:58:29 | 只看该作者
    看看。。。。。。。。。
    我是一个兵
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    
    关闭

    站长推荐上一条 /4 下一条

    QQ|手机版|Archiver|网站地图|小黑屋|守望者 ( 京ICP备14061876号

    GMT+8, 2024-4-20 02:41 , Processed in 0.085741 second(s), 34 queries .

    守望者AIR

    守望者AIR技术交流社区

    本站成立于 2014年12月31日

    快速回复 返回顶部 返回列表