加载 GIF 图像
假定我们有一个 JAR 文件其中包含我们的应用程序要使用的一组 gif 图像下面就是使用 JarResources 访问 JAR 文件中的图像文件的方法
JarResources jar = new JarResources (Imagesjar);
Image logo =
ToolkitgetDefaultToolkit()createImage (jargetResource (logogif);
这段代码说明我们可以创建一个 JarResources 对象并将其初始化为包含我们要使用的资源的 JAR 文件 Imagesjar随后我们使用 JarResources 的 getResource() 方法将来自 logogif 文件的原始数据提供给 AWT Toolkit 的 createImage() 方法
命名说明
JarResource 是一个非常简单的示例它说明了如何使用 Java 所提供的各种功能来处理 JAR 和 zip 档案文件
关于命名的简要说明Java 中的归档支持实际上是以流行的 zip 归档格式为起点的(请参阅 Java Tip : Use archive files to speed up applet loading)因此在最初实现处理档案文件的 Java 支持时所有类文件以及诸如此类的东西并未放在 javautilzip 包中这些类通常以 Zip 开头但在转向 Java 时功能已发生了变化档案文件的名称也更具有 Java 特征 因此现在我们称之为 JAR 文件的文件基本上是 zip 文件
工作方式
JarResources 类的重要数据域用来跟蹤和存储指定 JAR 文件的内容
public final class JarResources {
public boolean debugOn=false;
private Hashtable htSizes=new Hashtable();
private Hashtable htJarContents=new Hashtable();
private String jarFileName;
这样该类的实例化设置 JAR 文件的名称然后转到 init() 方法完成全部实际工作
public JarResources(String jarFileName) {
thisjarFileName=jarFileName;
init();
}
现在init() 方法只将指定 JAR 文件的整个内容加载到一个 hashtable(通过资源名访问)中
这是一个相当有用的方法下面我们对它作进一步的分析ZipFile 类为我们提供了对 JAR/zip 档案头信息的基本访问方法这类似于文件系统中的目录信息下面我们列出 ZipFile 中的所有条目并用档案中每个资源的大小添充 htSizes hashtable
private void init() {
try {
ZipFile zf=new ZipFile(jarFileName);
Enumeration e=zfentries();
while (ehasMoreElements()) {
ZipEntry ze=(ZipEntry)enextElement();
if (debugOn) {
Systemoutprintln(dumpZipEntry(ze));
}
htSizesput(zegetName()new Integer((int)zegetSize()));
}
zfclose();
接下来我们使用 ZipInputStream 类访问档案ZipInputStream 类完成了全部魔术允许我们单独读取档案中的每个资源我们从档案中读取组成每个资源的精确字节数并将其存储在 htJarContents hashtable 中您可以通过资源名访问这些数据
FileInputStream fis=new FileInputStream(jarFileName);
BufferedInputStream bis=new BufferedInputStream(fis);
ZipInputStream zis=new ZipInputStream(bis);
ZipEntry ze=null;
while ((ze=zisgetNextEntry())!=null) {
if (zeisDirectory()) {
continue;
}
if (debugOn) {
Systemoutprintln(
zegetName()=+zegetName()++getSize()=+zegetSize()
);
}
int size=(int)zegetSize();
// 表示大小未知
if (size==) {
size=((Integer)htSizesget(zegetName()))intValue();
}
byte[] b=new byte[(int)size];
int rb=;
int chunk=;
while (((int)size rb) > ) {
chunk=zisread(brb(int)size rb);
if (chunk==) {
break;
}
rb+=chunk;
}
// 添加到内部资源 hashtable 中
htJarContentsput(zegetName()b);
if (debugOn) {
Systemoutprintln(
zegetName()+ rb=+rb+
size=+size+
csize=+zegetCompressedSize()
);
}
}
} catch (NullPointerException e) {
Systemoutprintln(done);
} catch (FileNotFoundException e) {
eprintStackTrace();
} catch (IOException e) {
eprintStackTrace();
}
}
请注意用来标识每个资源的名称是档案中资源的限定路径名例如不是包中的类名 即 javautilzip 包中的 ZipEntry 类将被命名为 java/util/zip/ZipEntry而不是 javautilzipZipEntry
代码的最后一个重要部分是简单的测试驱动程序该测试驱动程序是一个简单的应用程序它接收 JAR/zip 档案名和资源名它试图发现档案中的资源文件然后将成功或失败的消息报告出来
public static void main(String[] args) throws IOException {
if (argslength!=) {
Systemerrprintln(
usage: java JarResources
);
Systemexit();
}
JarResources jr=new JarResources(args[]);
byte[] buff=jrgetResource(args[]);
if (buff==null) {
Systemoutprintln(Could not find +args[]+);
} else {
Systemoutprintln(Found +args[]+ (length=+bufflength+));
}
}
} // JarResources 类结束
您已了解了这个类一个易于使用的类它隐藏了使用打包在 JAR 文件中的资源的全部棘手问题
练习
现在您对从档案文件中提取资源已有了一定的认识下面是可用来修改和扩展 JarResources 类的一些说明
不在构造期间一次性加载全部内容而要延迟加载对于大型 JAR 文件构造期间可能没有足够的内存加载全部文件
不只是提供类似 getResource() 这样的一般读方法我们还可提供资源特定的读方法 例如用来返回 Java Image 对象的 getImage() 方法用来返回 Java Class 对象的 getClass() 方法(在自定义的类加载程序的协助下)等等如果 JAR 文件足够小则我们可以根据它们的扩展名(gifclass 等等)预先构建全部资源
某些方法应该提供关于给定 JAR 文件本身(基本上是 ZipFile 的包装)的信息包括Jar/zip 的条目数返回全部资源名的 Enumerator返回特定条目长度(和其他属性)的读方法允许编制索引的读方法这仅仅是举几个例子
可对 JarResources 进行扩展以供 applet 使用通过利用 applet 参数和 URLConnection 类就可以从网络上下载 JAR 内容而不是将档案作为本地文件打开此外我们还可将该类扩展为一个自定义的 Java 内容处理程序
小结
如果您曾经渴望知道如何从 JAR 文件中提取图像那么您现在已学到了一种方法有了本技巧提供的这个新类您就不仅可以用 JAR 文件处理图像而且可以将提取魔术用于 JAR 文件中的任何资源