利用JAVA API函数实现数据的压缩与解压缩

      利用JAVA API函数实现数据的压缩与解压缩

      


2:数据压缩结构图

ZIP VS GZIP

如果你是在Windows系统下工作,你可能会对工具WinZip很熟悉,是用来创建压缩档案和解开压缩档案的。而在UNIX平台上,会有一些不同,命令tar用来创建一个档案文件(并不压缩),其它的程序(gzipcompress)用来创建一个压缩档案。

WinZipPkZip之类的工具同时扮演着归档和压缩两个角色。他们将文件压缩并将其归档。另一方面,gzip并不将文件归档。所以,在UNIX平台上,命令tar通常用来创建一个档案文件,然后命令gzip来将档案文件压缩。

Java.util.zip

Java提供了java.util.zip包用来兼容ZIP格式的数据压缩。它提供了一系列的类用来读取,创建,修改ZIPGZIP格式的文件。它还提供了工具类来计算任意输入流的数目,这可以用来验证输入数据的有效性。该包提供了一个接口,十四个类,和两个异常处理类,如表1所示。

1: java.util.zip

条目

类型

描述

Checksum

接口

被类Adler32CRC32实现的接口

Adler32

使用Alder32算法来计算Checksum数目

CheckedInputStream

一个输入流,保存着被读取数据的Checksum

CheckedOutputStream

一个输出流,保存着被读取数据的Checksum

CRC32

使用CRC32算法来计算Checksum数目

Deflater

使用ZLIB压缩类,支持通常的压缩方式

DeflaterOutputStream

一个输出过滤流,用来压缩Deflater格式数据

GZIPInputStream

一个输入过滤流,读取GZIP格式压缩数据

GZIPOutputStream

一个输出过滤流,读取GZIP格式压缩数据

Inflater

使用ZLIB压缩类,支持通常的解压方式

InlfaterInputStream

一个输入过滤流,用来解压Inlfater格式的压缩数据

ZipEntry

存储ZIP条目

ZipFile

ZIP文件中读取ZIP条目

ZipInputStream

一个输入过滤流,用来读取ZIP格式文件中的文件

ZipOutputStream

一个输出过滤流,用来向ZIP格式文件口写入文件

DataFormatException

异常类

抛出一个数据格式错误

ZipException

异常类

抛出一个ZIP文件

 

注意:ZLIB压缩类最初是作为可移植的网络图像文件格式(PNG)标准的一部分开发的,是不受专利保护的。

ZIP文件中解压缩和提取数据

java.util.zip包提供了数据压缩与解压缩所需要的类。ZIP文件的解压缩实质上就是从输入流中读取数据。Java.util.zip包提供了类ZipInputStream来读取ZIP文件。ZipInputStream流的创建与其它输入流的创建没什么两样。举个例子,下面的代码段创建了一个输入流来读取ZIP格式的文件:

FileInputStream fis = new FileInputStream("figs.zip");
         
         
ZipInputStream zin = new ZipInputStream(new BufferedInputStream(fis));
         
         

      
      
       
        
      
      

 

ZIP输入流打开后,你可以使用getNextEntry方法来读取ZIP文件中的条目数,该方法返回一个ZipEntry对象。如果到达文件的尾部,getNextEntry返回null

ZipEntry entry;
         
         
while((entry = zin.getNextEntry()) != null) {
         
         
   // extract data
         
         
   // open output streams
         
         
}
         
         

      
      
       
        
      
      

 

现在,你应该建立一个输出流,如下所示:

int BUFFER = 2048;
         
         
FileOutputStream fos = new FileOutputStream(entry.getName());
         
         
BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER);
         
         

      
      
       
        
      
      

 

注意:在这段代码中我们用BufferedOutputStream代替了ZIPOutputStreamZIPOutputStreamGZIPOutputStream使用内置的512字节缓冲。当缓冲区的大小大于512字节时,使用BufferedOutputStream才是正确的(例子中设置为2048)。ZIPOutputStream不允许你设置缓冲区的大小,GZIPOutputStream也是一样,但创建 GZIPOutputStream 对象时可以通过构造函数的参数指定内置的缓冲尺寸。

这段代码中,使用ZIP内含的条目名称创建一个文件输出流。可以使用entry.getName来得到它的返回句柄。接着读出被压缩的源数据,然后写入输出流:

while ((count = zin.read(data, 0, BUFFER)) != -1) {
         
         
   //System.out.write(x);
         
         
   dest.write(data, 0, count);
         
         
}
         
         

      
      
       
        
      
      

 

最后,不要忘记关闭输入和输出流:

dest.flush();
         
         
dest.close();
         
         
zin.close();
         
         

      
      
       
        
      
      

 

例程1的源程序UnZip.java显示如何解压缩并从ZIP档案中将文件释放出来。测试这个例子,编译这个类,并运行它,传给它一个ZIP格式的文件作为参数:

prompt> java UnZip somefile.zip

注意somefile.zip应该是一个ZIP压缩档案,可以用任何一种ZIP压缩工具来创建,例如WinZip

例程1源代码:

UnZip.java
         
         
import java.io.*;
         
         
import java.util.zip.*;
         
         

       
       
        
         
       
       
public class UnZip {
         
         
   static final int BUFFER = 2048;
         
         
   public static void main (String argv[]) {
         
         
      try {
         
         
         BufferedOutputStream dest = null;
         
         
         FileInputStream fis = new 
         
         
       FileInputStream(argv[0]);
         
         
         ZipInputStream zis = new 
         
         
       ZipInputStream(new BufferedInputStream(fis));
         
         
         ZipEntry entry;
         
         
         while((entry = zis.getNextEntry()) != null) {
         
         
            System.out.println("Extracting: " +entry);
         
         
            int count;
         
         
            byte data[] = new byte[BUFFER];
         
         
            // write the files to the disk
         
         
            FileOutputStream fos = new 
         
         
          FileOutputStream(entry.getName());
         
         
            dest = new 
         
         
              BufferedOutputStream(fos, BUFFER);
         
         
            while ((count = zis.read(data, 0, BUFFER)) 
         
         
              != -1) {
         
         
               dest.write(data, 0, count);
         
         
            }
         
         
            dest.flush();
         
         
            dest.close();
         
         
         }
         
         
         zis.close();
         
         
      } catch(Exception e) {
         
         
         e.printStackTrace();
         
         
      }
         
         
   }
         
         
}
         
         

      
      
       
        
      
      

 

有一点值得大家注意,类ZipInputStream读出ZIP文件序列(简单地说就是读出这个ZIP文件压缩了多少文件),而类ZipFile使用内嵌的随机文件访问机制读出其中的文件内容,所以不必顺序的读出ZIP压缩文件序列。

注意ZIPInputStreamZipFile之间另外一个基本的不同点在于高速缓冲的使用方面。当文件使用ZipInputStreamFileInputStream流读出的时候,ZIP条目不使用高速缓冲。然而,如果使用ZipFile(文件名)来打开文件,它将使用内嵌的高速缓冲,所以如果ZipFile(文件名)被重复调用的话,文件只被打开一次。缓冲值在第二次打开进使用。如果你工作在UNIX系统下,这是什么作用都没有的,因为使用ZipFile打开的所有ZIP文件都在内存中存在映射,所以使用ZipFile的性能优于ZipInputStream。然而,如果同一ZIP文件的内容在程序执行期间经常改变,或是重载的话,使用ZipInputStream就成为你的首选了。

下面显示了使用类ZipFile来解压一个ZIP文件的过程:

1.       通过指定一个被读取的ZIP文件,或者是文件名,或者是一个文件对象来创建一个ZipFile对象:
ZipFile zipfile = new ZipFile("figs.zip");

2.       使用entries方法,返回一个枚举对象,循环获得文件的ZIP条目对象:
while(e.hasMoreElements()) {
entry = (ZipEntry) e.nextElement();
// read contents and save them
}

3.       ZIP条目作为参数传递给getInputStream方法,可以读取ZIP文件中指定条目的内容,能过其返回的输入流(InputStram)对象可以方便的读出ZIP条目的内容:
is = new BufferedInputStream(zipfile.getInputStream(entry));

4.       获取ZIP条目的文件名,创建输出流,并保存:
byte data[] = new byte[BUFFER];
FileOutputStream fos = new FileOutputStream(entry.getName());
dest = new BufferedOutputStream(fos, BUFFER);
while ((count = is.read(data, 0, BUFFER)) != -1) {
dest.write(data, 0, count);
}

5.       最后关闭所有的输入输出流 dest.flush();
dest.close();
is.close();

完整的程序代码如例程2所示。再次编译这个文件,并传递一个ZIP格式的文件做为参数:

prompt> java UnZip2 somefile.zip

例程2源码:

UnZip2.java 
         
         
import java.io.*;
         
         
import java.util.*;
         
         
import java.util.zip.*;
         
         

       
       
        
         
       
       
public class UnZip2 {
         
         
   static final int BUFFER = 2048;
         
         
   public static void main (String argv[]) {
         
         
      try {
         
         
         BufferedOutputStream dest = null;
         
         
         BufferedInputStream is = null;
         
         
         ZipEntry entry;
         
         
         ZipFile zipfile = new ZipFile(argv[0]);
         
         
         Enumeration e = zipfile.entries();
         
         
         while(e.hasMoreElements()) {
         
         
            entry = (ZipEntry) e.nextElement();
         
         
            System.out.println("Extracting: " +entry);
         
         
            is = new BufferedInputStream
         
         
              (zipfile.getInputStream(entry));
         
         
            int count;
         
         
            byte data[] = new byte[BUFFER];
         
         
            FileOutputStream fos = new 
         
         
              FileOutputStream(entry.getName());
         
         
            dest = new 
         
         
              BufferedOutputStream(fos, BUFFER);
         
         
            while ((count = is.read(data, 0, BUFFER)) 
         
         
              != -1) {
         
         
               dest.write(data, 0, count);
         
         
            }
         
         
            dest.flush();
         
         
            dest.close();
         
         
            is.close();
         
         
         }
         
         
      } catch(Exception e) {
         
         
         e.printStackTrace();
         
         
      }
         
         
   }
         
         
}
         
         

      
      
       
        
      
      

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值