Java核心技术卷I:基础知识(原书第8版):10.1 JAR文件

铁文整理

10.1 JAR文件

    在将应用程序进行打包时,使用者一定希望仅提供给其一个单独的文件,而不是一个含有大量类文件的目录,JAR文件就是为此目的而设计的。一个JAR文件既可以包含类文件,也可以包含诸如图像和声音这些其他类型的文件。此外,JAR文件是压缩的,它使用了大家熟悉的ZIP压缩格式。

    提示:Java SE 5.0提供了—种新的压缩方案,被称为pack200,这是一种较通常的ZIP压缩算法更加有效的压缩类文件的方式。Sun声称,对类文件的压缩率接近90%。有关更加详细的信息请参看网站http://java.sun.com/javase/6/docs/technotes/guide/deployment/deployment-guide/pack200.html

    可以使用JAR工具制作JAR文件(在默认的JDK安装中,位于jdk/bin目录下)。创建一个新的JAR文件应该使用的常见命令格式为:

    jar cvf JARFileName File1 File2 ...

    例如:

    jar cvf CalculatorClasses.jar *.class icon.gif

    通常,jar命令的格式如下:

    jar options Fiie1 File2 ...

    10-1列出了所有jar程序的可选项。它们类似于UNIX tar命令的选项。

10-1 jar程序选项

选项

说明

c

创建一个新的或者空的存档文件并加入文件。如果指定的文件名是目录,jar程序将会对它们进行递归处理。

C

暂时改变目录,例如:jar cvf JARFfileName.jar -C classes **class改变classes子目录,以便增加这些类文件

e

在清单中创建一个条目(请参看可执行的JAR文件)

f

JAR文件名指定为第二个命令行参数。如果没有这个参数,jar命令会将结果写到标准输出上(在创建JAR文件时)或者从标准输入中读取它(在解压或者列出JAR文件内容时)

i

建立索引文件(用于加快对大型归档的査找)

m

将一个清单文件添加到jar文件中。清单是对存档内容和来源的说明。每个归档有一个默认的清单文件,但是,如果想验证归档文件的内容,可以提供自己的清单文件

M

不为条目创建清单文件

t

显示内容表

u

更新一个已有的JAR文件

v

生成详细的输出结果

x

解压文件。如果提供一个或多个文件名,只解压这些文件,否则,解压所有文件

0

存储,不进行ZIP压缩

10.1.1 清单文件

    除了类文件、图像和其他资源外,每个JAR文件还包含一个用于描述归挡特征的清单文件。

    清单文件被命名为MANIFEST.MF,它位于JAR文件的一个特殊META-INFO子目录中。最小的符合标准的清单文件是很简单的:

    Manifest-Version: 1.0

    复杂的清单文件可能包含更多条目。这些清单条目被分成多个节。第一节被称为主节(main section)。它作用于整个JAR文件。随后的条目用来指定已命名条目的属性,这些已命名的条目可以是某个文件、包或者URL。它们都必须起始于名为Name的条目。节与节之间用空行分开。例如:

    Manifest-Version: 1.0

    描述这个归档文件的行

 

    Name: Woozle.class

    描述这个文件的行

 

    Name: com/mycompany/mypkg/

    描述这个包的行

    要想编辑清单文件,需要将希望添加到清单文件中的行放到文本文件中,然后运行:

    jar cfm JARFileName ManifestFileName ...

    例如,要创建一个包含清单的JAR文件,应该运行:

    jar cfm MyArchive.jar manifest.mf com/mycompany/mypkg/*.class

    要想更新一个已有的JAR文件的清单,则需要将增加的部分放置到一个文本文件中,然后执行下列命令:

    jar ufm MyArchive.jar manifest-additions.mf

    注释:请参看http://java.sun.com/javase/6/docs/technotes/guides获得有关JAR文件和清单文件格式的更多信息。

10.1.2 可运行JAR文件

    Java SE 6中,可以使用jar命令中的e选项指定程序的条目点,即通常需要在调用Java程序加载器时指定的类:

    jar cvfe MyProgram.jar com.mycompany.mypkg.MainAppClass files to add

    用户可以简单地通过下面命令来启动应用程序:

    java -jar MyProgram.jar

    在旧的JDK版本中,必须指定应用程序的主类,下面是这个处理命令:

    Main-Class: com.mycompary.mypkg.MainAppClass

    不要将扩展名.class添加到主类名中。然后运行jar命令:

    jar cvfm MyProgram.jar mainclass.mf files to add

    警告:清单文件的最后一行必须以换行符结束,否则,清单文件将无法被正确地读取。常见的错误是创建了一个只包含Main-Class而没有行结束符的文本文件。

    根据操作系统的配置,可以通过双击JAR文件图标来启动应用程序。下面是各种操作系统的操作方式:

  • Windows平台中,Java运行时安装器将建立一个扩展名为.jar的文件与javaw -jar命令相关联来启动文件(与java命令不同,javaw命令不打开shell窗口)。

  • Solaris平台中,操作系统能够识别JAR文件的“魔数”格式,并用java -jar命令启动它。

  • Mac OS平台中,操作系统能够识别.jar扩展名文件。当双击JAR文件时就会执行,Java程序可以运行。

    无论怎样,人们对JAR文件中的Java程序与本地文件有着不同的感觉。在Windows平台中,可以使用第三方的打包器工具将JAR文件转换成Windows可执行文件。打包器是一个大家熟知的扩展名为.exeWindows程序,它可以査找和加载Java虚拟机,或者在没有找到JVM时告诉用户应该做些什么。有许多商业的和开放的原始产品,比如,JSmoothLauch4J。开放的原始安装生成器IzPack还包含了一个本地加载器。有关这个问题的更加详细的信息请参看网站http://www.javalobby.org/articles/java2exe

    Macintosh平台中,这种情形处理起來会容易一写。应用程序打包工具MRJAppBuider可以将JAR文件转换成一个顶级的Mac程序,有关更加详细的信息请参看http://java.sun.com/developer/technicalArticles/JavaLP/JavaToMac3

10.1.3 资源

    applet和应用程序中使用的类通常需要使用一些相关的数据文件,例如:

  • 图像和声音文件。

  • 带有消息字符串和按钮标签的文本文件。

  • 二进制数据文件,例如,描述地图布局的文件。

    Java中,这些关联的文件被称为资源。

    注释:在Windows中,术语“资源”有着更加特殊的含义。Windows资源也是由图像、按钮标签等组成,但是它们都附属于可执行文件,并通过标准的程序设计访问。相比之下,Java资源作为单独的文件存储,并不是作为类文件的一部分存储,对资源的访问和解释由每个类自己胜任。

    例如,AboutPanel类显示了一条信息,如图10-1所示。

    当然,在面板中的书名和版权年限将会在出版下一版图书时发生变化。为了易于追踪这个变化,希望将文本放置在一个文件中,而不是以字符串的形式硬写到代码中。

    但是应该将about.txt这样的文件放在哪儿呢?显然,将它与其他程序文件一起放在JAR中是最方便的。

    类加载器知道如何搜索类文件,直到在类路径、存档文件或Web服务器上找到为止。利用资源机制,对于非类文件也可以同样方便地进行操作。下面是必要的步骤:

  1. 获得具有资源的Class对象,例如,AboutPanel.class

  2. 如果资源是一个图像或声音文件,那么就需要调用getResource(filename)获得作为URL的资源位置,然后利用getImagegetAudioClip方法进行读取。

  3. 与图像或声音文件不同,其他资源可以使用getResourceAsStream方法读取文件中的数据。

    重点在于类加载器可以记住如何定位类,然后在同一位置査找关联的资源。

    例如,要想利用about.gif图像文件制作图标,可以使用下列代码:

            URL url = ResourceTest.class.getResource("about.gif");

            Image img = Toolkit.getDefaultToolkit().getImage(url);

    这段代码的含义是“在找到ResourceTest类的地方定位about.gif文件”。

    要想读取about.txt文件,可以使用下列命令:

        InputStream stream = ResourceTest.class.getResourceAsStream("about.txt");

        Scanner in = new Scanner(stream);

    除了可以将资源文件与类文件放在同一个目录中外,还可以将它放在子目录中。可以使用下面所示的层级资源名:

    data/text/about.txt

    这是一个相对的资源名,它会被解释为相对于加载这个资源的类所在的包。注意,必须使用“/”作为分隔符,而不要理睬存储资源文件的系统实际使用哪种目录分隔符。例如,在Windows文件系统中,资源加载器会自动地将“/”转换成“\”。

    一个以“/”开头的资源名被称为绝对资源名,它的定位方式与类在包中的定位方式一样。

    例如,资源“/corejava/title.txt”定位于corejava目录下(它可能是类路径的一个子目录,也可能位于JAR文件中,对applet来说在Web务器上)。

    文件的自动装载是利用资源加载特性完成的。没有标准的方法来解释资源文件的内容。每个程序必须拥有解释资源文件的方法。

    另一个经常使用资源的地方是程序的国际化。与语言相关的字符串,如消息和用户界面标签都存放在资源文件中,每种语言对应一个文件。国际化AP将在卷II的第5章中进行讨论。这些API提供了组织和访问本地化文件的标准方法。

    10-1显示了这个程序的源代码。这个程序演示了资源加载。编译、创建JAR文件和执行这个程序的命令是:

    javac ResourceTest.java

    jar cvfm ResourceTest.jar ResourceTest.mf *.class *.gif *.txt

    java -jar ResoorceTest.jar

    JAR文件移到另外一个不同的目录中,再运行它,以便确认程序是从JAR文件中,而不是从当前目录中读取的资源。

10-1 ResourceTest.java

import java.awt.*;

import java.io.*;

import java.net.*;

import java.util.*;

import javax.swing.*;

 

/**

 * @version 1.4 2007-04-30

 * @author Cay Horstmann

 */

public class ResourceTest {

    public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable() {

            public void run() {

                ResourceTestFrame frame = new ResourceTestFrame();

                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                frame.setVisible(true);

            }

        });

    }

}

 

/**

 * A frame that loads image and text resources.

 */

class ResourceTestFrame extends JFrame {

    public ResourceTestFrame() {

        setTitle("ResourceTest");

        setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);

        URL aboutURL = getClass().getResource("about.gif");

        Image img = Toolkit.getDefaultToolkit().getImage(aboutURL);

        setIconImage(img);

 

        JTextArea textArea = new JTextArea();

        InputStream stream = getClass().getResourceAsStream("about.txt");

        Scanner in = new Scanner(stream);

        while (in.hasNext())

            textArea.append(in.nextLine() + "\n");

        add(textArea);

    }

 

    public static final int DEFAULT_WIDTH = 300;

    public static final int DEFAULT_HEIGHT = 300;

}

APIjava.lang.Class 1.0

  • URL getResource(String name) 1.1

  • InputStream getResourceAsStream(String name) 1.1:找到与类位于同一位置的资源,返回一个可以加载资源的URL或者输入流。如果没有找到资源,则返回null,而且不会抛出异常或者发生I/O错误。

10.1.4 密封

    在第4章曾经提到过,可以将Java包密封(seal)以保证不会有其他的类加入到其中。如果在代码中使用了包可见的类、方法和域,就可能希望密封包。如果不密封,其他类就有可能放在这个包中,进而访问包可见的特性。

    例如,如果密封了com.mycompany.util包,就不能用下面的语句顶替密封包之外的类:

package com.mycompany.util;

    要想密封一个包,需要将包中的所有类放到一个JAR文件中。在默认情况下,JAR文件中的包是没有密封的。可以在清单文件的主节中加入下面一行:

    Sealed: true

    来改变全局的默认设定。对于每个单独的包,可以通过在JAR文件的清单中增加—节,来指定是否想要密封这个包。例如:

    Name: com/Mycompany/util/

    Sealed: true

 

    Name: com/mycompany/misc/

    Sealed: false

    要想密封一个包,需要创建一个包含清单指令的文本文件。然后用常规的方式运行jar命令:

    jar cvfm MyArchive.jar manifest.mf files to add


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值