zoukankan      html  css  js  c++  java
  • Java实现文件压缩与解压[zip格式,gzip格式]

    Java实现ZIP的解压与压缩功能基本都是使用了Java的多肽和递归技术,可以对单个文件和任意级联文件夹进行压缩和解压,对于一些初学者来说是个很不错的实例。

    zip扮演着归档和压缩两个角色;gzip并不将文件归档,仅只是对单个文件进行压缩,所以,在UNIX平台上,命令tar通常用来创建一个档案文件,然后命令gzip来将档案文件压缩。
    Java I/O类库还收录了一些能读写压缩格式流的类。要想提供压缩功能,只要把它们包在已有的I/O类的外面就行了。这些类不是Reader和Writer,而是InputStream和OutStreamput的子类。这是因为压缩算法是针对byte而不是字符的。
    相关类与接口:
    Checksum 接口:被类Adler32和CRC32实现的接口
    Adler32 :使用Alder32算法来计算Checksum数目
    CRC32 :使用CRC32算法来计算Checksum数目

    CheckedInputStream :InputStream派生类,可得到输入流的校验和Checksum,用于校验数据的完整性
    CheckedOutputStream :OutputStream派生类,可得到输出流的校验和Checksum, 用于校验数据的完整性

    DeflaterOutputStream :压缩类的基类。 
    ZipOutputStream :DeflaterOutputStream的一个子类,把数据压缩成Zip文件格式。
    GZIPOutputStream :DeflaterOutputStream的一个子类,把数据压缩成GZip文件格式

    InflaterInputStream :解压缩类的基类
    ZipInputStream :InflaterInputStream的一个子类,能解压缩Zip格式的数据
    GZIPInputStream :InflaterInputStream的一个子类,能解压缩Zip格式的数据

    ZipEntry 类:表示 ZIP 文件条目
    ZipFile 类:此类用于从 ZIP 文件读取条目

    使用ZIP对多个文件进行压缩与解压

    Java对Zip格式类库支持得比较全面,得用它可以把多个文件压缩成一个压缩包。这个类库使用的是标准Zip格式,所以能与很多的压缩工具兼容。
    ZipOutputStream类有设置压缩方法以及在压缩方式下使用的压缩级别,zipOutputStream.setMethod(int method)设置用于条目的默认压缩方法。只要没有为单个 ZIP 文件条目指定压缩方法,就使用ZipOutputStream所设置的压缩方法来存储,默认值为 ZipOutputStream.DEFLATED(表示进行压缩存储),还可以设置成STORED(表示仅打包归档存储)。ZipOutputStream在设置了压缩方法为DEFLATED后,我们还可以进一步使用setLevel(int level)方法来设置压缩级别,压缩级别值为0-9共10个级别(值越大,表示压缩越利害),默认为Deflater.DEFAULT_COMPRESSION=-1。当然我们也可以通过条目ZipEntry的setMethod方法为单个条件设置压缩方法。

    类ZipEntry描述了存储在ZIP文件中的压缩文件。类中包含有多种方法可以用来设置和获得ZIP条目的信息。类ZipEntry是被ZipFile[zipFile.getInputStream(ZipEntry entry)]和ZipInputStream使用来读取ZIP文件,ZipOutputStream来写入ZIP文件的。有以下这些有用的方法:getName()返回条目名称、isDirectory()如果为目录条目,则返回 true(目录条目定义为其名称以 '/' 结尾的条目)、setMethod(int method) 设置条目的压缩方法,可以为 ZipOutputStream.STORED 或 ZipOutputStream .DEFLATED。

    下面实例我们使用了apache的zip工具包(所在包为ant.jar ),因为java类型自带的不支持中文路径,不过两者使用的方式是一样的,只是apache压缩工具多了设置编码方式的接口,其他基本上是一样的。另外,如果使用org.apache.tools.zip.ZipOutputStream来压缩的话,我们只能使用org.apache.tools.zip.ZipEntry来解压,而不能使用java.util.zip.ZipInputStream来解压读取了,当然apache并未提供ZipInputStream类。

    文件压缩:

    package gizAction;
    import java.io.*;
    import java.util.zip.*;
    /**
     * @author Dana·Li
     * <p>
     * 程序实现了ZIP压缩[compression]
     * <p>
     * 大致功能包括用了多态,递归等JAVA核心技术,可以对单个文件和任意级联文件夹进行压缩和解压。 需在代码中自定义源输入路径和目标输出路径。
     * <p>
     * 在本段代码中,实现的是压缩部分
     */
    public class ZipCompressing {
        private int k = 1; // 定义递归次数变量
        
        private void zip(String zipFileName, File inputFile) throws Exception {
            System.out.println("压缩中...");
            ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFileName));
            BufferedOutputStream bo = new BufferedOutputStream(out);
            zip(out, inputFile, inputFile.getName(), bo);
            bo.close();
            out.close(); // 输出流关闭
            System.out.println("压缩完成");
        }
        private void zip(ZipOutputStream out, File f, String base,
                BufferedOutputStream bo) throws Exception { // 方法重载
            if (f.isDirectory()){
                File[] fl = f.listFiles();
                if (fl.length == 0){
                    out.putNextEntry(new ZipEntry(base + "/")); // 创建zip压缩进入点base
                    System.out.println(base + "/");
                }
                for (int i = 0; i < fl.length; i++) {
                    zip(out, fl[i], base + "/" + fl[i].getName(), bo); // 递归遍历子文件夹
                }
                System.out.println("第" + k + "次递归");
                k++;
            } else {
                out.putNextEntry(new ZipEntry(base)); // 创建zip压缩进入点base
                System.out.println(base);
                FileInputStream in = new FileInputStream(f);
                BufferedInputStream bi = new BufferedInputStream(in);
                int b;
                while ((b = bi.read()) != -1) {
                    bo.write(b); // 将字节流写入当前zip目录
                }
                bi.close();
                in.close(); // 输入流关闭
            }
        }
        /**
         * 测试
         * @param args
         */
        public static void main(String[] args) {
            ZipCompressing book = new ZipCompressing();
            try {
                book.zip("F:\ziptest.zip",new File("F:\ziptest"));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    文件解压:

    package gizAction;
    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.zip.ZipEntry;
    import java.util.zip.ZipInputStream;
    /**
     * @author Dana·Li
     * <p>
     * 程序实现了ZIP解压[decompression]
     * <p>
     * 大致功能包括用了多态,递归等JAVA核心技术,可以对单个文件和任意级联文件夹进行压缩和解压。 需在代码中自定义源输入路径和目标输出路径。
     * <p>
     * 在本段代码中,实现的是解压部分;
     */ 
    public class zipDecompressing {  
    
        public static void main(String[] args) {  
            // TODO Auto-generated method stub  
            long startTime=System.currentTimeMillis();  
            try {  
                ZipInputStream Zin=new ZipInputStream(new FileInputStream(  
                        "F:\ziptest.zip"));//输入源zip路径  
                BufferedInputStream Bin=new BufferedInputStream(Zin);  
                String Parent="F:\ziptest\"; //输出路径(文件夹目录)  
                File Fout=null;  
                ZipEntry entry;  
                try {  
                    while((entry = Zin.getNextEntry())!=null && !entry.isDirectory()){  
                        Fout=new File(Parent,entry.getName());  
                        if(!Fout.exists()){  
                            (new File(Fout.getParent())).mkdirs();  
                        }  
                        FileOutputStream out=new FileOutputStream(Fout);  
                        BufferedOutputStream Bout=new BufferedOutputStream(out);  
                        int b;  
                        while((b=Bin.read())!=-1){  
                            Bout.write(b);  
                        }  
                        Bout.close();  
                        out.close();  
                        System.out.println(Fout+"解压成功");      
                    }  
                    Bin.close();  
                    Zin.close();  
                } catch (IOException e) {  
                    e.printStackTrace();  
                }  
            } catch (FileNotFoundException e) {  
                e.printStackTrace();  
            }  
            long endTime=System.currentTimeMillis();  
            System.out.println("耗费时间: "+(endTime-startTime)+" ms");  
        }  
    
    }  

    用GZIP进行对单个文件压缩

    GZIP的接口比较简单,因此如果你只需对一个流进行压缩的话,可以使用它。当然它可以压缩字符流,与可以压缩字节流,下面是一个对GBK编码格式的文本文件进行压缩的。
    压缩类的用法非常简单;只要用GZIPOutputStream 或ZipOutputStream把输出流包起来,再用GZIPInputStream 或ZipInputStream把输入流包起来就行了。剩下的都是些普通的I/O操作。 

    import java.io.BufferedOutputStream;
    import java.io.BufferedReader;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.zip.GZIPInputStream;
    import java.util.zip.GZIPOutputStream;
    public class GZIPcompress {
        public static void main(String[] args) throws IOException {
            //做准备压缩一个字符文件,注,这里的字符文件要是GBK编码方式的
            BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(
                    "e:/tmp/source.txt"), "GBK"));
            //使用GZIPOutputStream包装OutputStream流,使其具体压缩特性,最后会生成test.txt.gz压缩包
            //并且里面有一个名为test.txt的文件
            BufferedOutputStream out = new BufferedOutputStream(new GZIPOutputStream(
                    new FileOutputStream("test.txt.gz")));
            System.out.println("开始写压缩文件...");
            int c;
            while ((c = in.read()) != -1) {
    
                /* 
                 * 注,这里是压缩一个字符文件,前面是以字符流来读的,不能直接存入c,因为c已是Unicode
                 * 码,这样会丢掉信息的(当然本身编码格式就不对),所以这里要以GBK来解后再存入。
                 */
                out.write(String.valueOf((char) c).getBytes("GBK"));
            }
            in.close();
            out.close();
            System.out.println("开始读压缩文件...");
            //使用GZIPInputStream包装InputStream流,使其具有解压特性
            BufferedReader in2 = new BufferedReader(new InputStreamReader(
                    new GZIPInputStream(new FileInputStream("test.txt.gz")), "GBK"));
            String s;
            //读取压缩文件里的内容
            while ((s = in2.readLine()) != null) {
                System.out.println(s);
            }
            in2.close();
        }
    }

    参考资料:

    http://www.oschina.net/code/snippet_12_259

    http://blog.csdn.net/kevin_luan/article/details/7903400

    http://jiangzhengjun.iteye.com/blog/517186

    本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须且在文章页面明显位置给出原文链接Dana、Li(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请留言或加Q群!
  • 相关阅读:
    【流量劫持】SSLStrip 终极版 —— location 瞒天过海
    【流量劫持】沉默中的狂怒 —— Cookie 大喷发
    【流量劫持】SSLStrip 的未来 —— HTTPS 前端劫持
    Web 前端攻防(2014版)
    流量劫持 —— 浮层登录框的隐患
    流量劫持能有多大危害?
    流量劫持是如何产生的?
    XSS 前端防火墙 —— 整装待发
    XSS 前端防火墙 —— 天衣无缝的防护
    XSS 前端防火墙 —— 无懈可击的钩子
  • 原文地址:https://www.cnblogs.com/visec479/p/4112881.html
Copyright © 2011-2022 走看看