java io------压缩

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

压缩类 功能
CheckedInputStream GetCheckSum()为任何InputStream 产生校验和(不仅是解压)
CheckedOutputStream GetCheckSum()为任何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)