多數
java
程序員都非常清楚使用
jar
文件將組成
java
解決方案的各種資源(即
.class
文件、聲音和圖像)打包的優點。剛開始使用
jar
文件的人常問的一個問題是:“如何從
jar
文件中提取圖像呢?”本文將回答這個問題,并會提供一個類,這個類使從
jar
文件中提取任何資源變得非常簡單!
加載
gif
圖像
???
假定我們有一個
jar
文件,其中包含我們的應用程序要使用的一組
.gif
圖像。下面就是使用
JarResources
訪問
jar
文件中的圖像文件的方法:
???
JarResources JR=new JarResources("GifBundle.jar");
????
Image logo=Toolkit.getDefaultToolkit().createImage(JR.getResources("logo.gif"));
????
這段代碼說明我們可以創建一個
JarResources
對象,并將其初始化為包含我們要使用的資源的
jar
文件
--
images.jar
。隨后我們使用
JarResources
的
getResource()
方法將來自
logo.gif
文件的原始數據提供給
awt Toolkit
的
createImage()
方法。
命名說明
JarResource
是一個非常簡單的示例,它說明了如何使用
java
所提供的各種功能來處理
jar
和
zip
檔案文件。
?
工作方式
JarReources
類的重要數據域用來跟蹤和存儲指定
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 {
????????? // extracts just sizes only.
??????????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
中,您可以通過資源名訪問這些數據:
?????
????????? // extract resources and put them into the 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 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();
?????? }
?? }
請注意,用來標識每個資源的名稱是檔案中資源的限定路徑名,例如,不是包中的類名
--
即
java.util.zip
包中的
ZipEntry
類將被命名為
"java/util/zip/ZipEntry"
,而不是
"java.util.zip.ZipEntry"
。
其它方法
:
??? /**
??? * Dumps a zip entry into a string.
??? * @param ze a ZipEntry
??? */
?? private String dumpZipEntry(ZipEntry ze) {
?????? StringBuffer sb=new StringBuffer();
?????? if (ze.isDirectory()) {
????????? sb.append("d ");
???????} else {
????????? sb.append("f ");
???????}
?????? if (ze.getMethod()==ZipEntry.STORED) {
????????? sb.append("stored?? ");
???????} else {
????????? sb.append("defalted ");
?????? }
?????? sb.append(ze.getName());
?????? sb.append("\t");
?????? sb.append(""+ze.getSize());
?????? if (ze.getMethod()==ZipEntry.DEFLATED) {
????????? sb.append("/"+ze.getCompressedSize());
?????? }
?????? return (sb.toString());
?? }
??? /**
??? * Extracts a jar resource as a blob.
??? * @param name a resource name.
??? */
?? public byte[] getResource(String name) {
????? return (byte[])htJarContents.get(name);
?? }
?????
代碼的最后一個重要部分是簡單的測試驅動程序。該測試驅動程序是一個簡單的應用程序,它接收
jar/zip
檔案名和資源名。它試圖發現檔案中的資源文件,然后將成功或失敗的消息報告出來:
public static void main(String[] args) throws IOException {
?????? if (args.length!=2) {
????????? System.err.println(
???????????? "usage: java JarResources < jar file name> < resource name>"
???????????? );
????????? 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
文件處理圖像,而且可以將提取魔術用于
jar
文件中的
任何
資源。
?