Jungleford's Home BlogJava分舵

          Java技術(shù)研究,兼探討歷史話題

          BlogJava 首頁 新隨筆 聯(lián)系 聚合 管理
            24 Posts :: 0 Stories :: 53 Comments :: 0 Trackbacks

          jungleford如是說

              可能有不少初學(xué)者會有這樣的困惑(以前我也有過):在你的代碼里調(diào)用了一些資源文件,如圖片,音樂等,在調(diào)試環(huán)境或單獨運行的時候可以正常顯示或播放,而一旦打包到j(luò)ar文件中,這些東東就再也出不來了,除非把這個jar放到原來未打包以前的目錄下,但通常jar是單獨發(fā)布的。這里介紹一個解決這類問題的方法。

          getResource和getResourceAsStream

              問題的根源還是在于老生常談的所謂class path,不信的話你在系統(tǒng)環(huán)境變量里的ClassPath加上你的jar文件,這下你就看得到你的圖片了!但單獨發(fā)布jar的話不可能指望每次都讓用戶為你的jar而專門修改classpath。那么有沒有什么辦法一勞永逸地搞定它呢?我們需要從類的裝載入手。先扯遠一點,在開發(fā)JSP之類的Web應(yīng)用程序的時候要用到第三方的庫怎么辦?通常的做法是把這些庫(可以是class,也可以是jar)統(tǒng)統(tǒng)放到WEB-INF/lib/目錄下面,為什么這樣系統(tǒng)就認了呢?因為Web容器(譬如Tomcat)在裝載類的時候有自己的組織方式(可以參考Tomcat手冊)。特別地,jar也是類裝載器的一個可訪問媒介,ClassLoader提供了兩個方法用于從裝載的類路徑中取得資源:

          public URL getResource(String name);
          public InputStream getResourceAsStream(String name);


          這里name是資源的類路徑,它是相對與“/”根路徑下的位置。getResource得到的是一個URL對象來定位資源,而getResourceAsStream取得該資源輸入流的引用保證程序可以從正確的位置抽取數(shù)據(jù)。
              真正使用的不是ClassLoader的這兩個方法,而是Class的getResource和getResourceAsStream方法,因為Class對象可以從你的類得到(如YourClass.class或YourClass.getClass()),而ClassLoader則需要再調(diào)用一次YourClass.getClassLoader()方法,但根據(jù)JDK文檔的說法,Class對象的這兩個方法其實是“委托”(delegate)給裝載它的ClassLoader來做的,所以只需要使用Class對象的這兩個方法就可以了。
              在參考資料中有一篇老外寫的文章比較深入介紹了從jar中裝載資源的方法。

          一個應(yīng)用的例子

              以下是在我寫的一個小工具MSNHistoryCombiner中用到的一段代碼,可以從jar中裝載圖片和文本信息。譬如,你的jar中根目錄下有個img目錄,里面放有一些圖片,如img1.jpg,你可以這樣調(diào)用

          Utilities.getImageFromJar("/img/img1.jpg", YourClass.class);


          注意必須這里是“/img/img1.jpg”而非“img/img1.jpg”。從jar中讀文本資源也是類似方法調(diào)用getTextFromJar。
              需要說明的是,這段代碼也不是我原創(chuàng)的,是從一段別的代碼中經(jīng)過修改得到的,但原代碼的來源忘記了,在這里向原作者表示感謝和歉意。

          import java.io.*;
          import java.awt.
          *;

          public class Utilities
          {
            
          /**
             * <p>
             * Description: Return an Image based on the supplied image identifier. The
             * image is assumed to reside at the defined location within the same
             * repository as this class.
             
          */

            
          public static Image getImageFromJar(final String imageId, Class c)
            
          {
              
          // Image reference initialised to null (the image may not be found).
              Image image = null;
              
          // Open a resource stream on the supplied image identifier.
              final InputStream inputStream = c.getResourceAsStream(imageId);
              
          // If the image data is found
              if (inputStream != null)
              
          {
                
          // Open a byte array output stream so that we can create a byte
                
          // array with which to create the image.
                final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                
          // Attempt to copy the source image data into the byte array
                
          // stream, and then create an image from the result.
                try
                
          {
                  
          // Read/write image data in 1k chunks.
                  final byte[] bytes = new byte[1024];
                  
          int read = 0;
                  
          while ((read = inputStream.read(bytes)) >= 0)
                  
          {
                    byteArrayOutputStream.write(bytes, 
          0, read);
                  }


                  
          // Create an image from the resulting byte array.
                  image = Toolkit.getDefaultToolkit().createImage(
                      byteArrayOutputStream.toByteArray());
                }

                
          catch (IOException exception)
                
          {
                  exception.printStackTrace();
                }

              }

              
          return image;
            }


            
          public static String getTextFromJar(final String filename, Class c)
            
          {
              String text 
          = "";
              
          // Open a resource stream on the supplied file name.
              final InputStream inputStream = c.getResourceAsStream(filename);
              
          // If the file is found
              if (inputStream != null)
              
          {
                final BufferedReader 
          in = new BufferedReader(new InputStreamReader(
                    inputStream));
                
          try
                
          {
                  String s;
                  
          while ((s = in.readLine()) != null)
                  
          {
                    text 
          += s + "\n";
                  }

                }

                
          catch (IOException exception)
                
          {
                  exception.printStackTrace();
                }

              }

              
          return text;
            }

          }


          參考資料

          J2SE API Documentation

          用 One-JAR 簡化應(yīng)用程序交付

          posted on 2005-06-11 12:41 jungleford 閱讀(2985) 評論(2)  編輯  收藏 所屬分類: 咖啡屋 - Java 技術(shù)研究

          Feedback

          # re: 從Jar包獲取資源的方法 2006-02-28 09:52 skyswan
          如果不知道具體的資源文件名,想列出所有的資源,怎么做呢?  回復(fù)  更多評論
            

          # re: 從Jar包獲取資源的方法 2006-03-11 19:09 jungleford
          @skyswan
          我沒有具體作過,但我想作為jar包,java.util.jar中的工具應(yīng)該可以找到所有資源吧  回復(fù)  更多評論
            

          主站蜘蛛池模板: 漳州市| 荆州市| 德庆县| 昌宁县| 年辖:市辖区| 图片| 通城县| 富平县| 庐江县| 南城县| 聂拉木县| 定日县| 疏附县| 房山区| 临夏市| 策勒县| 山西省| 兴和县| 徐水县| 耿马| 马关县| 潢川县| 灵寿县| 和静县| 宁乡县| 新巴尔虎右旗| 读书| 安阳县| 崇文区| 莱西市| 尖扎县| 德清县| 陈巴尔虎旗| 资阳市| 花莲市| 乌兰浩特市| 莲花县| 汝州市| 平远县| 墨脱县| 夹江县|