发信人: consultant() 
整理人: zjxyz(2002-01-26 13:57:56), 站内信件
 | 
 
 
如何从JAR和ZIP包中析取Java源文件
                                                录入/江湖小子
                                                  1999.08.07
 
 
 摘 要: 
 
 将Java 源 文 件 打 包 成JAR 文 件, 可 以 减 少 下 载 时、 增 强 安 全 
  性 和 易 管 理 性。 本 文 将 讨 论 如 何 从JAR 文 件 中
 提 取Java 源 文 件。 
 
 绝 大 多 数Java 程 序 员 非 常 善 于 利 用JAR 文 件 的 优 势 将 各 种  
 包 含Java 解 决 方 案 的 资 源 进 行 打 包。 面 对JAR 文
 件, 人 们 询 问 的 一 个 普 遍 问 题 是:“ 我 何 从 一 个JAR 文 件 中 
  提 取 出 一 个 图 象 文 件 ?”。 本 文 将 回 答 这 个
 问 题, 并 且 提 供 一 个Java 类, 它 可 以 容 易 地 从 一 个JAR 文 件 
  中 析 取 出 任 意 一 个 文 件。 
 
 加 载 一 个GIF 文 件
 
 假 设 我 们 有 一 个 包 含 一 些.GIF 图 象 文 件 的JAR 文 件, 这 些 图 
  象 文 件 将 在 应 用 程 序 中 被 使 用。 以 下 是 我 们
 使 用 JarResources 类 从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 类 访 问 压 缩 文 档。 ZipInputSt 
 ream 类 完 成 了 所 有 的 工 作 以 使 我 们 能 读 出 压
 缩 文 档 中 任 意 一 个 资 源。 我 们 从 包 含 每 个 资 源 的 压 缩 文 
  档 中 读 出 准 确 数 目 的 字 节, 并 将 它 们 存 储 在
 一 个 可 由 资 源 名 访 问 的 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 中 的 任 何 资 源 上 表 演 你 的
 解 压 魔 术。 
 
 
 
 -- 有求皆苦,无欲则刚
  ※ 修改:.consultant 于 Feb 18 09:20:18 修改本文.[FROM: 210.78.138.191] ※ 来源:.月光软件站 http://www.moon-soft.com.[FROM: 210.78.138.191]
  | 
 
 
 |