天天看點

如何從 JAR 和 zip 檔案檔案中提取 Java 資源

多數 java 程式員都非常清楚使用 JAR 檔案将組成 java 解決方案的各種資源(即 .class 檔案、聲音和圖像)打包的優點。(如果您不熟悉 JAR 檔案,請參閱後文的 參考資源部分。)剛開始使用 JAR 檔案的人常問的一個問題是:“如何從 JAR 檔案中提取圖像呢?”本文将回答這個問題,并會提供一個類,這個類使從 JAR 檔案中提取任何資源變得非常簡單!

加載 GIF 圖像

假定我們有一個 JAR 檔案,其中包含我們的應用程式要使用的一組 .gif 圖像。下面就是使用 JarResources 通路 JAR 檔案中的圖像檔案的方法:

    JarResources jar = new JarResources ("Images.jar");     Image logo =  Toolkit.getDefaultToolkit().createImage (jar.getResource ("logo.gif");

這段代碼說明我們可以建立一個

JarResources

對象,并将其初始化為包含我們要使用的資源的 JAR 檔案 --

Images.jar

。随後我們使用

JarResources

getResource()

方法将來自 logo.gif 檔案的原始資料提供給 AWT Toolkit 的

createImage()

方法。

命名說明

JarResource 是一個非常簡單的示例,它說明了如何使用 java 1.1 所提供的各種功能來處理 JAR 和 zip 檔案檔案。

關于命名的簡要說明。Java 中的歸檔支援實際上是以流行的 zip 歸檔格式為起點的(請參閱 "Java Tip 21: Use archive files to speed up applet loading")。是以,在最初實作處理檔案檔案的 java 支援時,所有類檔案以及諸如此類的東西并未放在 java.util.zip 包中;這些類通常以 "

Zip

" 開頭。但在轉向 java 1.1 時,功能已發生了變化,檔案檔案的名稱也更具有 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) {       this.jarFileName=jarFileName;       init();    }

現在,

init()

方法隻将指定 JAR 檔案的整個内容加載到一個 hashtable(通過資源名通路)中。

這是一個相當有用的方法,下面我們對它作進一步的分析。

ZipFile

類為我們提供了對 JAR/zip 檔案頭資訊的基本通路方法。這類似于檔案系統中的目錄資訊。下面我們列出

ZipFile

中的所有條目,并用檔案中每個資源的大小添充 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 hashtable 中,您可以通過資源名通路這些資料:

          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 表示大小未知。              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;              }              // 添加到内部資源 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();        }    }

請注意,用來辨別每個資源的名稱是檔案中資源的限定路徑名,例如,不是包中的類名 -- 即 java.util.zip 包中的

ZipEntry

類将被命名為 "java/util/zip/ZipEntry",而不是 "java.util.zip.ZipEntry"。

代碼的最後一個重要部分是簡單的測試驅動程式。該測試驅動程式是一個簡單的應用程式,它接收 JAR/zip 檔案名和資源名。它試圖發現檔案中的資源檔案,然後将成功或失敗的消息報告出來:

   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+").");        }    } } // JarResources 類結束。

您已了解了這個類。一個易于使用的類,它隐藏了使用打包在 JAR 檔案中的資源的全部棘手問題。

練習

現在您對從檔案檔案中提取資源已有了一定的認識,下面是可用來修改和擴充

JarResources

類的一些說明:

  • 不在構造期間一次性加載全部内容,而要延遲加載。對于大型 JAR 檔案,構造期間可能沒有足夠的記憶體加載全部檔案。
  • 不隻是提供類似

    getResource()

    這樣的一般讀方法,我們還可提供資源特定的讀方法 -- 例如,用來傳回 java

    Image

    對象的

    getImage()

    方法,用來傳回 java

    Class

    對象的

    getClass()

    方法(在自定義的類加載程式的協助下),等等。如果 JAR 檔案足夠小,則我們可以根據它們的擴充名(.gif、.class 等等)預先建構全部資源。
  • 某些方法應該提供關于給定 JAR 檔案本身(基本上是

    ZipFile

    的包裝)的資訊,包括:Jar/zip 的條目數;傳回全部資源名的 Enumerator;傳回特定條目長度(和其他屬性)的讀方法;允許編制索引的讀方法,這僅僅是舉幾個例子。
  • 可對

    JarResources

    進行擴充,以供 applet 使用。通過利用 applet 參數和

    URLConnection

    類,就可以從網絡上下載下傳 JAR 内容,而不是将檔案作為本地檔案打開。此外,我們還可将該類擴充為一個自定義的 java 内容處理程式。

小結

如果您曾經渴望知道如何從 JAR 檔案中提取圖像,那麼您現在已學到了一種方法。有了本技巧提供的這個新類,您就不僅可以用 JAR 檔案處理圖像,而且可以将提取魔術用于 JAR 檔案中的任何資源。

作者簡介

Arthur Choi 目前是 IBM 的一位顧問程式員。他曾先後在幾個公司任職,包括 SamSung Network Laboratory 和 MITRE。他參與過的項目包括客戶機/伺服器系統、分布式對象計算和網絡管理。他在各種作業系統環境下用過多種語言。他于 1981 年開始用 FORTRAN IV 和 COBOL 進行程式設計。後來他轉向 C 和 C++,最近兩年他一直在用 Java 工作。他最感興趣的 Java 應用是廣域網中的資料倉庫和網際網路上的并行處理和分布式處理(使用基于代理的程式設計)。Reach Arthur 的電子郵件位址為 [email protected]。

John Mitchell,先後做過雇員、咨詢人員,現在是自己公司的老闆,過去十年他所投資的領域包括前沿計算機軟體的開發、對其他開發人員提供建議和教育訓練。他的咨詢範圍包括 java 技術、編譯器、解釋器、基于 Web 應用和網際網路商務等。John 是 Making Sense of java: A Guide for Managers and the Rest of Us 一書的作者之一,并在程式設計雜志上發表了許多文章。除了為 JavaWorld 撰寫 java Tips 專欄之外,他還主持着 comp.lang.tcl.announce 和 comp.binaries.geos 新聞討論區。Reach John 的電子郵件位址為 [email protected]。

參考資源

  • 這是類檔案

    JarResources.java

    JarResources.java
  • JARs

    http://www.javasoft.com/products/jdk/1.1/docs/guide/jar/index.html

  • 有關 java 的歸檔支援的詳細資訊,請參閱 "Java Tip 21: Use archive files to speed up applet loading"

    http://www.javaworld.com/javatips/jw-javatip21.html  

下一篇: 虛拟機備份