如 何 从JAR 和ZIP 包 中 析 取Java 源 文 件
----
摘 要:
----
将Java 源 文 件 打 包 成JAR 文 件, 可 以 减 少 下 载 时、 增 强 安 全 性 和 易 管 理 性。 本 文 将 讨 论 如 何 从JAR 文 件 中 提 取Java 源 文 件。
----
绝 大 多 数Java 程 序 员 非 常 善 于 利 用JAR 文 件 的 优 势 将 各 种 包 含Java 解 决 方 案 的 资 源 进 行 打 包。 面 对JAR 文 件, 人 们 询 问 的 一 个 普 遍 问 题 是:“ 我 何 从 一 个JAR 文 件 中 提 取 出 一 个 图 象 文 件 ?”。 本 文 将 回 答 这 个 问 题, 并 且 提 供 一 个Java 类, 它 可 以 容 易 地 从 一 个JAR 文 件 中 析 取 出 任 意 一 个 文 件。
加 载 一 个GIF 文 件
----
假 设 我 们 有 一 个 包 含 一 些.GIF 图 象 文 件 的JAR 文 件, 这 些 图 象 文 件 将 在 应 用 程 序 中 被 使 用。 以 下 是 我 >
Transfer interrupted!
arResources 类 从JAR 文 件 中 析 取 一 个 图 象 文 件 的 代 码:
----
JarResources jar = new JarResources ("Images.jar");
----
Image logo =
----
Toolkit.getDefaultToolkit().createImage (jar.getResource ("logo.gif");
----
上 面 代 码 的 含 义 是: 我 们 建 立 一 个JavaResources 对 象, 并 将 它 初 始 化 为 一 个 包 含 我 们 感 兴 趣 资 源 的JAR 文 件 -- Images.jar。 然 后 我 们 使 用JavaResources 类 的getResource() 方 法 从logo.gif 取 出 原 始 数 据, 然 后 调 用AWT 工 具 箱 的createImage() 方 法 从 原 始 数 据 建 立 一 个Image 对 象 实 例。
有 关 命 名 的 注 释
----
JarResource 是 一 个 相 当 容 易 理 解 的 例 子, 它 解 释 了 如 何 使 用Java 1.1 提 供 的 各 种 功 能 处 理JAR 和ZIP 压 缩 文 档 文 件。
----
关 于 命 名 的 的 简 单 解 释。Java 对 压 缩 文 档 的 支 持 实 际 上 起 源 于 使 用 一 般 的ZIP 压 缩 文 档 格 式。 因 此,Java 中 实 现 压 缩 档 案 操 作 的 类 都 被 放 入java.util.zip 包 中; 这 些 类 一 般 以“Zip.” 开 始。 但 是Java 升 级 到 了1.1 版 以 后, 压 缩 文 档 的 命 名 变 得 以Java 为 中 心 了。 从 此, 我 们 所 说 的JAR 压 缩 文 档 基 本 上 还 是zip 文 件。
代 码 具 体 的 工 作 流 程
----
JavaResources 类 中 的 一 些 重 要 字 段 用 来 跟 踪 和 存 储 指 定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) {
this.jarFileName=jarFileName;
init();
}
----
现 在,init() 方 法 把 指 定JAR 文 件 的 全 部 内 容 装 入 到 一 个 杂 凑 表(hashtable) 中( 杂 凑 表 名 可 以 从 资 源 名 进 行 访 问)
----
init() 是 一 个 功 能 相 当 强 大 的 方 法, 让 我 们 来 逐 步 理 解 它 的 功 能。ZipFile 类 使 我 们 基 本 上 能 访 问JAR/Zip 压 缩 文 档 的 头 部 信 息。 这 和 一 个 文 件 系 统 的 目 录 信 息 相 似。 在 这 里 我 们 列 出Zip 文 件 的 所 有 条 目(entry), 并 且 按 照 文 档 中 的 每 个 资 源 的 尺 寸 创 建htSizes 杂 凑 表(hashtable)。
private void init() {
try {
ZipFile zf=new ZipFile(jarFileName);
Enumeration e=zf.entries();
while (e.hasMoreElements()) {
ZipEntry ze=(ZipEntry)e.nextElement();
if (debugOn) {
System.out.println(dumpZipEntry(ze));
}
htSizes.put(ze.getName(),new Integer((int)ze.getSize()));
}
zf.close();
----
下 一 步, 我 们 使 用ZipInputStream 类 访 问 压 缩 文 档。ZipInputStream 类 完 成 了 所 有 的 工 作 以 使 我 们 能 读 出 压 缩 文 档 中 任 意 一 个 资 源。 我 们 从 包 含 每 个 资 源 的 压 缩 文 档 中 读 出 准 确 数 目 的 字 节, 并 将 它 们 存 储 在 一 个 可 由 资 源 名 访 问 的htJarContents 杂 凑 表 中。
FileInputStream fis=new FileInputStream(jarFileName);
BufferedInputStream bis=new BufferedInputStream(fis);
ZipInputStream zis=new ZipInputStream(bis);
ZipEntry ze=null;
while ((ze=zis.getNextEntry())!=null) {
if (ze.isDirectory()) {
continue;
}
if (debugOn) {
System.out.println(
"ze.getName()="+ze.getName()+","+"getSize()="+ze.getSize()
);
}
int size=(int)ze.getSize();
// -1 means unknown size.
if (size==-1) {
size=((Integer)htSizes.get(ze.getName())).intValue();
}
byte[] b=new byte[(int)size];
int rb=0;
int chunk=0;
while (((int)size - rb) > 0) {
chunk=zis.read(b,rb,(int)size - rb);
if (chunk==-1) {
break;
}
rb+=chunk;
}
// add to internal resource hashtable
htJarContents.put(ze.getName(),b);
if (debugOn) {
System.out.println(
ze.getName()+" rb="+rb+
",size="+size+
",csize="+ze.getCompressedSize()
);
}
}
} catch (NullPointerException e) {
System.out.println("done.");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
----
注 意, 用 来 确 定 每 个 资 源 的 名 字 是 压 缩 文 档 中 资 源 的 实 际 路 径 名, 而 不 是 包(package) 中 类 的 名 字。 也 就 是 说,java.util.zip 包 中 的ZipEntry 类 的 名 字 应 为“java/util/zip.ZipEntry”, 而 不 是"java.util.zip.ZipEntry"。
----
这 段 代 码 最 后 一 个 重 要 部 分 是 一 个 简 单 测 试 程 序。 这 个 测 试 程 序 能 提 取 一 个 压 缩 文 档 名 和 资 源 名。 它 寻 找 压 缩 文 档 中 的 资 源 并 报 告 运 行 成 功 与 否。
public static void main(String[] args) throws IOException {
if (args.length!=2) {
System.err.println(
"usage: java JarResources "
);
System.exit(1);
}
JarResources jr=new JarResources(args[0]);
byte[] buff=jr.getResource(args[1]);
if (buff==null) {
System.out.println("Could not find "+args[1]+".");
} else {
System.out.println("Found "+args[1]+ " (length="+buff.length+").");
}
}
} // End of JarResources class.
----
现 在 你 知 道 怎 么 做 了。 这 个 易 于 使 用 的 类 隐 藏 了 所 有 使 用 压 缩 文 档 中 的 资 源 的 复 杂 实 现 细 节。
结 论
----
如 果 你 急 于 想 知 道 怎 样 从 一 个JAR 压 缩 文 档 中 解 出 一 个 图 象, 那 么 现 在 你 已 拥 有 了 一 种 方 法。 你 不 仅 能 处 理 和JAR 文 件 相 关 的 图 象, 而 且 你 还 能 使 用 这 篇 文 章 提 供 了 新 类, 在JAR 中 的 任 何 资 源 上 表 演 你 的 解 压 魔 术。
编 译: 刘 小 兵
文 章 来 源:http://www.javaworld.com/javaworld/javatips/jw-javatip49.html
中国计算机世界出版服务公司版权所有
|