37.JAVA编程思想——JAVA IO 压缩

37.JAVA编程思想——JAVA IO 压缩

Java 1.1 也添加一个类,用以支持对压缩格式的数据流的读写。它们封装到现成的 IO类中,以提供压缩功能。

此时Java 1.1 的一个问题显得非常突出:它们不是从新的Reader 和Writer 类衍生出来的,而是属于InputStream和 OutputStream层次结构的一部分。所以有时不得不混合使用两种类型的数据流(注意可用InputStreamReader和OutputStreamWriter 在不同的类型间方便地进行转换)。

Java 1.1 压缩类 功能

CheckedInputStream GetCheckSum()为任何InputStream产生校验和(不仅是解压)

CheckedOutputStream GetCheckSum()为任何OutputStream产生校验和(不仅是解压)

DeflaterOutputStream 用于压缩类的基础类

ZipOutputStream 一个DeflaterOutputStream,将数据压缩成Zip文件格式

GZIPOutputStream 一个DeflaterOutputStream,将数据压缩成GZIP 文件格式

InflaterInputStream 用于解压类的基础类

ZipInputStream 一个DeflaterInputStream,解压用 Zip文件格式保存的数据

GZIPInputStream 一个DeflaterInputStream,解压用GZIP 文件格式保存的数据

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

用 GZIP 进行简单压缩

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

import java.io.*;

import java.util.zip.*;

public classGZIPcompress {

    public static void main(String[] args) {

        try {

            BufferedReaderin = new BufferedReader(new FileReader(args[0]));

            BufferedOutputStreamout= newBufferedOutputStream(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");

            BufferedReaderin2= newBufferedReader(

                    new InputStreamReader(new GZIPInputStream(new FileInputStream("test.gz"))));

            Strings;

            while ((s = in2.readLine()) != null)

                System.out.println(s);

        }catch(Exception e) {

            e.printStackTrace();

        }

    }

} /// :~

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

用 Zip 进行多文件保存

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

代码:

import java.io.*;

import java.util.*;

import java.util.zip.*;

public classZipCompress {

    public static void main(String[] args) {

        try {

            FileOutputStreamf = new FileOutputStream("test.zip");

            CheckedOutputStreamcsum= newCheckedOutputStream(f,newAdler32());

            ZipOutputStreamout= newZipOutputStream(newBufferedOutputStream(csum));

            out.setComment("A test of Java Zipping");

            // Can't read the above comment, though

            for (int i = 0; i < args.length; i++) {

                System.out.println("Writing file "+ args[i]);

                BufferedReaderin = new BufferedReader(new FileReader(args[i]));

                out.putNextEntry(new ZipEntry(args[i]));

                int c;

                while ((c = in.read()) != -1)

                    out.write(c);

                in.close();

            }

            out.close();

            // Checksum valid only after the file

            // has been closed!

            System.out.println("Checksum: "+ csum.getChecksum().getValue());

            // Now extract the files:

            System.out.println("Reading file");

            FileInputStreamfi = new FileInputStream("test.zip");

            CheckedInputStreamcsumi= newCheckedInputStream(fi,newAdler32());

            ZipInputStreamin2= newZipInputStream(newBufferedInputStream(csumi));

            ZipEntryze;

            System.out.println("Checksum: "+ csumi.getChecksum().getValue());

            while ((ze = in2.getNextEntry()) != null) {

                System.out.println("Reading file "+ ze);

                int x;

                while ((x = in2.read()) != -1)

                    System.out.write(x);

            }

            in2.close();

            // Alternative way to open and read

            // zip files:

            ZipFilezf= newZipFile("test.zip");

            Enumeratione = zf.entries();

            while (e.hasMoreElements()) {

                ZipEntryze2= (ZipEntry) e.nextElement();

                System.out.println("File: "+ ze2);

                // ... and extract the data as before

            }

        }catch(Exception e) {

            e.printStackTrace();

        }

    }

} /// :~

执行:

Checksum: 1923287158

Reading file

Checksum: 1

对于要加入压缩档的每一个文件,都必须调用 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库时并不仅仅限于文件——可以压缩任何东西,包括要通过网络连接发送的数据。

Java 归档(jar )实用程序

Zip格式亦在Java 1.1 的 JAR(Java ARchive)文件格式中得到了采用。这种文件格式的作用是将一系列文件合并到单个压缩文件里,就象Zip那样。然而,同Java 中其他任何东西一样,JAR 文件是跨平台的,所以不必关心涉及具体平台的问题。除了可以包括声音和图像文件以外,也可以在其中包括类文件。

涉及因特网应用时,JAR文件显得特别有用。在 JAR文件之前,Web 浏览器必须重复多次请求Web服务器,以便下载完构成一个“程序片”(Applet)的所有文件。除此以外,每个文件都是未经压缩的。但在将所有这些文件合并到一个JAR 文件里以后,只需向远程服务器发出一次请求即可。同时,由于采用了压缩技术,所以可在更短的时间里获得全部数据。另外,JAR文件里的每个入口(条目)都可以加上数字化签名。

一个JAR文件由一系列采用 Zip压缩格式的文件构成,同时还有一张“详情单”,对所有这些文件进行了描述(可创建自己的详情单文件;否则,jar程序会为我们代劳)。在联机用户文档中,可以找到与JAR 详情单更多的资料(详情单的英语是“Manifest”)。

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

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

其中,“选项”用一系列字母表示(不必输入连字号或其他任何指示符)。如下所示:

c 创建新的或空的压缩档

t 列出目录表

x 解压所有文件

x file 解压指定文件

f 指出“我准备向你提供文件名”。若省略此参数,jar 会假定它的输入来自标准输入;或者在它创建文件时,输出会进入标准输出内

m 指出第一个参数将是用户自建的详情表文件的名字

v 产生详细输出,对 jar做的工作进行巨细无遗的描述

O 只保存文件;不压缩文件(用于创建一个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 程序工作时反馈更详尽的信息。

如果用O 选项创建了一个JAR文件,那个文件就可置入自己的类路径(CLASSPATH)中:

CLASSPATH="lib1.jar;lib2.jar;"

Java 能在lib1.jar 和 lib2.jar 中搜索目标类文件。

jar工具的功能没有zip工具那么丰富。例如,不能够添加或更新一个现成 JAR 文件中的文件,只能从头开始新建一个 JAR文件。此外,不能将文件移入一个 JAR文件,并在移动后将它们删除。然而,在一种平台上创建的JAR 文件可在其他任何平台上由jar工具毫无阻碍地读出(这个问题有时会困扰zip工具)。

你可能感兴趣的:(37.JAVA编程思想——JAVA IO 压缩)