java io------压缩

本文深入探讨了Java中的压缩技术,包括GZIP和Zip格式的使用方法。介绍了如何使用GZIPOutputStream和ZipOutputStream进行文件压缩,以及如何利用ZipInputStream和GZIPInputStream进行解压。此外,还讲解了如何利用ZipEntry处理多个文件和目录,以及如何使用Checksum类进行文件校验。

  Java IO 类库中的类支持读写格式的数据流,你可以用它们对其他的IO类进行封装,以提供压缩功能。
  这些类不是从新的Reader 和Writer 类衍生出来的,而是属于InputStream 和OutputStream 层次结构的一部分。这样做是因为压缩类库是按字节方式而不是字符方式处理的。所以有时不得不混合使用两种类型的数据流(注意可用InputStreamReader 和OutputStreamWriter 在不同的类型间方便地进行转换)。

压缩类功能
CheckedInputStreamGetCheckSum()为任何InputStream 产生校验和(不仅是解压)
CheckedOutputStreamGetCheckSum()为任何OutputStream 产生校验和(不仅是解压)
DeflaterOutputStream用于压缩类的基础类
ZipOutputStream一个DeflaterOutputStream,将数据压缩成Zip 文件格式
GZIPOutputStream一个DeflaterOutputStream,将数据压缩成GZIP 文件格式
InflaterInputStream用于解压类的基础类
ZipInputStream一个DeflaterInputStream,解压用Zip 文件格式保存的数据
GZIPInputStream一个DeflaterInputStream,解压用GZIP 文件格式保存的数据

尽管存在许多种压缩算法,但是Zip 和GZIP 可能最常用的。所以能够很方便地用多种现成的工具来读写这些格式的压缩数据。

1.用G Z I P 进行简单压缩

  GZIP 接口非常简单,所以如果只有单个数据流需要压缩(而不是一系列不同的数据),那么它就可能是最适当选择。下面是对单个文件进行压缩的例子:

//: io/GZIPcompress.java
// {Args: GZIPcompress.java}
import java.util.zip.*;
import java.io.*;

public class GZIPcompress {
  public static void main(String[] args)
  throws IOException {
    if(args.length == 0) {
      System.out.println(
        "Usage: \nGZIPcompress file\n" +
        "\tUses GZIP compression to compress " +
        "the file to test.gz");
      System.exit(1);
    }
    BufferedReader in = new BufferedReader(
      new FileReader(args[0]));
    BufferedOutputStream out = new BufferedOutputStream(
      new GZIPOutputStream(
        new FileOutputStream("test.gz")));
    System.out.println("Writing file");
    int c;
    while((c = in.read()) != -1)
      out.write(c);
    in.close();
    out.close();
    System.out.println("Reading file");
    BufferedReader in2 = new BufferedReader(
      new InputStreamReader(new GZIPInputStream(
        new FileInputStream("test.gz"))));
    String s;
    while((s = in2.readLine()) != null)
      System.out.println(s);
  }
} /* (Execute to see output) *///:~

  压缩类的用法非常直观——只需将输出流封装到一个GZIPOutputStream 或者ZipOutputStream 内,并将输入流封装到GZIPInputStream 或者ZipInputStream 内即可。剩余的全部操作就是标准的IO 读写。然而,这是一个很典型的例子,我们不得不混合使用新旧IO 流:数据的输入使用Reader 类,而GZIPOutputStream 的构建器只能接收一个OutputStream 对象,不能接收Writer 对象。

2.用Z i p 进行多文件保存

  支持Zip格式的Java库更加全面。利用该库可以方便地保存多个文件。甚至有一个独立的类来简化对Zip 文件的读操作。这个库采用的是标准Zip 格式,所以能与当前因特网上使用的大量压缩、解压工具很好地协作。下面这个例子采取了与前例相同的形式,但能根据我们需要控制任意数量的命令行参数。除此之外,它展示了如何用Checksum 类来计算和校验文件的“校验和”(Checksum )。可选用两种类型的Checksum:Adler32(速度要快一些)和CRC32(慢一些,但更准确)。

//: io/ZipCompress.java
// Uses Zip compression to compress any
// number of files given on the command line.
// {Args: ZipCompress.java}
import java.util.zip.*;
import java.io.*;
import java.util.*;
import static net.mindview.util.Print.*;

public class ZipCompress {
  public static void main(String[] args)
  throws IOException {
    FileOutputStream f = new FileOutputStream("test.zip");
    CheckedOutputStream csum =
      new CheckedOutputStream(f, new Adler32());
     ZipOutputStream zos = new ZipOutputStream(csum);
     BufferedOutputStream out =
      new BufferedOutputStream(zos);
    zos.setComment("A test of Java Zipping");
    // No corresponding getComment(), though.
    for(String arg : args) {
      print("Writing file " + arg);
      BufferedReader in =
        new BufferedReader(new FileReader(arg));
      zos.putNextEntry(new ZipEntry(arg));
      int c;
      while((c = in.read()) != -1)
        out.write(c);
      in.close();
      out.flush();
    }
    out.close();
    // Checksum valid only after the file has been closed!
    print("Checksum: " + csum.getChecksum().getValue());
    // Now extract the files:
    print("Reading file");
    FileInputStream fi = new FileInputStream("test.zip");
    CheckedInputStream csumi =
      new CheckedInputStream(fi, new Adler32());
    ZipInputStream in2 = new ZipInputStream(csumi);
    BufferedInputStream bis = new BufferedInputStream(in2);
    ZipEntry ze;
    while((ze = in2.getNextEntry()) != null) {
      print("Reading file " + ze);
      int x;
      while((x = bis.read()) != -1)
        System.out.write(x);
    }
    if(args.length == 1)
    print("Checksum: " + csumi.getChecksum().getValue());
    bis.close();
    // Alternative way to open and read Zip files:
    ZipFile zf = new ZipFile("test.zip");
    Enumeration e = zf.entries();
    while(e.hasMoreElements()) {
      ZipEntry ze2 = (ZipEntry)e.nextElement();
      print("File: " + ze2);
      // ... and extract the data as before
    }
    /* if(args.length == 1) */
  }
} /* (Execute to see output) *///:~

  对于要加入压缩档的每一个文件,都必须调用putNextEntry(),并将其传递给一个ZipEntry 对象。ZipEntry 对象包含了一个功能全面的接口,利用它可以获取和设置Zip 文件内那个特定的Entry(入口)上能够接受的所有数据:名字、压缩后和压缩前的长度、日期、CRC 校验和、额外字段的数据、注释、压缩方法以及它是否一个目录入口等等。然而,虽然Zip 格式提供了设置密码的方法,但Java 的Zip 库没有提供这方面的支持。而且尽管CheckedInputStream 和CheckedOutputStream 同时提供了对Adler32 和CRC32 校验和的支持,但是ZipEntry 只支持CRC 的接口。这虽然属于基层Zip 格式的限制,但却限制了我们使用速度更快的Adler32。

  为解压文件,ZipInputStream 提供了一个getNextEntry()方法,能在有的前提下返回下一个ZipEntry。作为一个更简洁的方法,可以用ZipFile 对象读取文件。该对象有一个entries()方法,可以为ZipEntry 返回一个Enumeration(枚举)。

  为读取校验和,必须拥有对关联的Checksum 对象的访问权限。在这里保留了指向CheckedOutputStream和CheckedInputStream 对象的引用。但是,也可以只占有指向Checksum 对象的引用。Zip 流中一个令人困惑的方法setComment()。正如前面展示的那样,我们可在写一个文件时设置注释内容,但却没有办法取出ZipInputStream 内的注释。看起来,似乎只能通过ZipEntry 逐个入口地提供对注释的完全支持。
  当然,使用GZIP 或Zip 库时并不仅仅限于文件——可以压缩任何东西,包括要通过网络连接发送的数据。

3.Java档案文件

  Zip 格式在JAR(Java ARchive)文件格式中得到了采用。这种文件格式的作用是将一系列文件合并到单个压缩文件里,就象Zip 那样。然而,同Java 中其他任何东西一样,JAR 文件是跨平台的,所以不必关心涉及具体平台的问题。除了可以包括声音和图像文件以外,也可以在其中包括类文件。
  JAR文件非常有用,尤其在涉及因特网应用时。在JAR 文件之前,Web 浏览器必须重复多次请求Web 服务器,以便下载完构成一个“程片”(Applet)的所有文件。除此以外,每个文件都是未经压缩的。但在将所有这些文件合并到一个JAR 文件里以后,只需向远程服务器发出一次请求即可。同时,由于采用了压缩技术,所以可在更短的时间里获得全部数据。另外,JAR 文件里的每个入口(条目)都可以加上数字化签名(详情参考Java 用户文档)。
  一个JAR 文件由一系列采用Zip 压缩格式的文件构成,同时还有一张“详情单”,对所有这些文件进行了描述(可创建自己的详情单文件;否则,jar 程序会为我们代劳)。在联机用户文档中,可以找到与JAR 详情单更多的资料(详情单的英语是“Manifest”)。

  jar 实用程序已与Sun 的JDK 配套提供,可以按我们的选择自动压缩文件。请在命令行调用它:

jar [选项] 说明 [详情单] 输入文件

option描述
c创建新的或空的压缩档
t列出目录表
x解压所有文件
x file解压指定文件
f指出“我准备向你提供文件名”。若省略此参数,jar 会假定它的输入来自标准输入;或者在它创建文件时,输出会进入标准输出内
m指出第一个参数将是用户自建的详情表文件的名字
v产生详细输出,描述jar所做的工作
0(数字零)只保存文件;不压缩文件(用于创建一个JAR 文件,以便我们将其置入自己的类路径中)
M不自动生成详情表文件

  在准备进入JAR 文件的文件中,若包括了一个子目录,那个子目录会自动添加,其中包括它自己的所有子目录,以此类推。路径信息也会得到保留。

下面是调用jar 的一些典型方法:

jar cf myJarFile.jar *.class
用于创建一个名为myJarFile.jar 的JAR 文件,其中包含了当前目录中的所有类文件,同时还有自动产生的详情表文件。

jar cmf myJarFile.jar myManifestFile.mf *.class
与前例类似,但添加了一个名为myManifestFile.mf 的用户自建详情表文件。

jar tf myJarFile.jar
生成myJarFile.jar 内所有文件的一个目录表。

jar tvf myJarFile.jar
添加“verbose”(详尽)标志,提供与myJarFile.jar 中的文件有关的、更详细的资料。

jar cvf myApp.jar audio classes image
假定audio,classes 和image 是子目录,这样便将所有子目录合并到文件myApp.jar 中。其中也包括了“verbose”标志,可在jar 程序工作时反馈更详尽的信息。

如果用0(零)选项创建了一个JAR 文件,那个文件就可置入自己的类路径(CLASSPATH)中:
CLASSPATH=”lib1.jar;lib2.jar;”
Java 能在lib1.jar 和lib2.jar 中搜索目标类文件。

Java实现压缩与解压缩ZIP   import java.io.BufferedInputStream;   import java.io.BufferedOutputStream;   import java.io.File;   import java.io.FileInputStream;   import java.io.FileOutputStream;   import java.util.zip.ZipEntry;   import java.util.zip.ZipOutputStream;   public class Zip {   static final int BUFFER = 2048;   public static void main(String argv[]) {   try {   BufferedInputStream origin = null;   FileOutputStream dest = new FileOutputStream("E:\\test\\myfiles.zip");   ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(   dest));   byte data[] = new byte[BUFFER];   File f = new File("e:\\test\\a\\");   File files[] = f.listFiles();   for (int i = 0; i < files.length; i++) {   FileInputStream fi = new FileInputStream(files[i]);   origin = new BufferedInputStream(fi, BUFFER);   ZipEntry entry = new ZipEntry(files[i].getName());   out.putNextEntry(entry);   int count;   while ((count = origin.read(data, 0, BUFFER)) != -1) {   out.write(data, 0, count);   }   origin.close();   }   out.close();   } catch (Exception e) {   e.printStackTrace();   }   }   }   解压缩的   import java.io.BufferedInputStream;   import java.io.BufferedOutputStream;   import java.io.File;   import java.io.FileOutputStream;   import java.util.Enumeration;   import java.util.zip.ZipEntry;   import java.util.zip.ZipFile;   public class UnZip {   static final int BUFFER = 2048;   public static void main(String argv[]) {   try {   String fileName = "E:\\test\\myfiles.zip";   String filePath = "E:\\test\\";   ZipFile zipFile = new ZipFile(fileName);   Enumeration emu = zipFile.entries();   int i=0;   while(emu.hasMoreElements()){   ZipEntry entry = (ZipEntry)emu.nextElement();   //会把目录作为一个file读出一次,所以只建立目录就可以,之下的文件还会被迭代到。   if (entry.isDirectory())   {   new File(filePath + entry.getName()).mkdirs();   continue;   }   BufferedInputStream bis = new BufferedInputStream(zipFile.getInputStream(entry));   File file = new File(filePath + entry.getName());   //加入这个的原因是zipfile读取文件是随机读取的,这就造成可能先读取一个文件   //而这个文件所在的目录还没有出现过,所以要建出目录来。   File parent = file.getParentFile();   if(parent != null && (!parent.exists())){   parent.mkdirs();   }   FileOutputStream fos = new FileOutputStream(file);   BufferedOutputStream bos = new BufferedOutputStream(fos,BUFFER);   int count;   byte data[] = new byte[BUFFER];   while ((count = bis.read(data, 0, BUFFER)) != -1)   {   bos.write(data, 0, count);   }   bos.flush();   bos.close();   bis.close();   }   zipFile.close();   } catch (Exception e) {   e.printStackTrace();   }   }   }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值