在Java的程序發布中,很多人會選擇采用二進制的jar的格式進行發布,怎么樣讀取Jar里面的資源呢?
主要是采用ClassLoader的下面幾個方法來實現:
public URL getResource(String name);
public InputStream getResourceAsStream(String name)
public static InputStream getSystemResourceAsStream(String name)
public static URL getSystemResource(String name)
我一般都是使用:
getClass().getResource(...);
比如,設置JFrame的圖標:
this.setIconImage(new ImageIcon(getClass().getResource(...)).getImage());
但是我今天遇到的問題是,在程序中需要播放一個存放在jar中的notify.wav聲音文件,我的代碼:
System.out.println(getClass().getResource("/sound/notify.wav").getPath());
System.out.println(getClass().getResource("/sound/notify.wav").getFile());
System.out.println(getClass().getResource("/sound/notify.wav").toExternalForm());
System.out.println(getClass().getResource("/sound/notify.wav").toString());
/*
//輸出的路徑
/D:/soft/test/bin/sound/notify.wav
/D:/soft/test/bin/sound/notify.wav
file:/D:/soft/test/bin/sound/notify.wav
file:/D:/soft/test/bin/sound/notify.wav
*/
FileInputStream audioFIS = new FileInputStream(getClass().getResource("/sound/notify.wav").getFile());
AudioPlayer.player.start(audioFIS); //播放聲音
在eclipse中測試的時候,能正常播放聲音,但打包成jar文件后,就提示找不到聲音文件了。
為什么在最上面的設置窗口的圖標時,可以,但在這里播放jar中的聲音文件時就出錯了呢?
最后通過在網上搜索,找到這篇介紹(http://www.iteye.com/topic/483115)才明白:
摘抄一部分內容:...........................
這主要是因為jar包是一個單獨的文件而非文件夾,絕對不可能通過"file:/e:/.../ResourceJar.jar/resource /res.txt"這種形式的文件URL來定位res.txt。所以即使是相對路徑,也無法定位到jar文件內的txt文件(讀者也許對這段原因解釋有些費解,在下面我們會用一段代碼運行的結果來進一步闡述)。
因為".../ResourceJar.jar!/resource/...."並不是文件資源定位符的格式 (jar中資源有其專門的URL形式: jar:<url>!/{entry} )。所以,如果jar包中的類源代碼用File f=new File(相對路徑);的形式,是不可能定位到文件資源的。這也是為什么源代碼1打包成jar文件后,調用jar包時會報出FileNotFoundException的症結所在了。
//解決辦法也很簡單,直接使用:getClass().getResourceAsStream()
InputStream audioIS = getClass().getResourceAsStream("/sound/notify.wav");;
AudioPlayer.player.start(audioIS);
2012-01-29