獲取Java程序運行的路徑

對於Java程序,無論是未打包的還是打包的JAR或WAR文件,有時候都需要獲取它運行所在目錄信息,如何做到這一點呢?

在Java處理的文件系統中,目錄的表示方式有兩種:

(1)絕對目錄,它以"/"爲起始字符,代表從根目錄下開始尋找給出的目錄,如/c:/java

(2)相對路徑,它以不帶“/”的目錄名錶示,表示以當前Java程序正在運行的目錄作爲起始目錄來尋找給出的目錄。如java/classes。在相對路徑中,有一些特定的字符,可以代表特的的目錄,比如,“.”代表當前目錄,“..”代表當前目錄的上一級目錄。在網上很多給出的例子中,就是利用"."作爲目錄名,構造File對象的實例,然後通過File對象的方法來獲取當前程序運行的目錄。

這種方法雖然簡單,但有時不能正確的得出當前程序的運行目錄。原因在於,運行Java程序不一定要進入到該程序的類文件或JAR文件所在的目錄,只要在運行時指定了正確的類路徑信息,就可以在任何目錄中運行Java程序,此時利用這種方法只能得到發出運行命令時所在的目錄信息。

從上面的分析可以看出,對於很多Java程序,尤其是WEB程序,利用當前路徑的“.”表示法,都不能滿足要求。那麼怎樣才能正確的得到運行目錄信息呢?

在Web程序中,利用Servlet API可以獲得一些路徑信息,比如HttpServletRequest接口中定義的getRealPath方法,但類似這些方法都依賴於Servlet環境,不便於程序的單元測試。

本文提供了一種只使用Java標準API的路徑探測方法,就是利用ClassLoader抽象類。

利用java.lang.Class的getClassLoader方法,可以獲得給定類的ClassLoader實例,它的getResource方法可以獲得當前類裝載器中的資源的位置,我們可以利用類文件的名稱作爲要查找的資源,經過處理後就可獲得當前Java程序的運行位置信息,其僞代碼如下:

獲得Class參數的所在的類名
取得該類所在的包名
將包名轉換爲路徑
利用getResource得到當前的類文件所在URL
利用URL解析出當前Java程序所在的路徑

具體代碼如下:
[code]

/**-----------------------------------------------------------------------
*getAppPath需要一個當前程序使用的Java類的class屬性參數,它可以返回打包過的
*Java可執行文件(jar,war)所處的系統目錄名或非打包Java程序所處的目錄
*@param cls爲Class類型
*@return 返回值爲該類所在的Java程序運行的目錄
-------------------------------------------------------------------------*/
public static String getAppPath(Class cls){
//檢查用戶傳入的參數是否爲空
if(cls==null)
throw new java.lang.IllegalArgumentException("參數不能爲空!");
ClassLoader loader=cls.getClassLoader();
//獲得類的全名,包括包名
String clsName=cls.getName()+".class";
//獲得傳入參數所在的包
Package pack=cls.getPackage();
String path="";
//如果不是匿名包,將包名轉化爲路徑
if(pack!=null){
String packName=pack.getName();
//此處簡單判定是否是Java基礎類庫,防止用戶傳入JDK內置的類庫
if(packName.startsWith("java.")||packName.startsWith("javax."))
throw new java.lang.IllegalArgumentException("不要傳送系統類!");
//在類的名稱中,去掉包名的部分,獲得類的文件名
clsName=clsName.substring(packName.length()+1);
//判定包名是否是簡單包名,如果是,則直接將包名轉換爲路徑,
if(packName.indexOf(".")<0) path=packName+"/";
else{//否則按照包名的組成部分,將包名轉換爲路徑
int start=0,end=0;
end=packName.indexOf(".");
while(end!=-1){
path=path+packName.substring(start,end)+"/";
start=end+1;
end=packName.indexOf(".",start);
}
path=path+packName.substring(start)+"/";
}
}
//調用ClassLoader的getResource方法,傳入包含路徑信息的類文件名
java.net.URL url =loader.getResource(path+clsName);
//從URL對象中獲取路徑信息
String realPath=url.getPath();
//去掉路徑信息中的協議名"file:"
int pos=realPath.indexOf("file:");
if(pos>-1) realPath=realPath.substring(pos+5);
//去掉路徑信息最後包含類文件信息的部分,得到類所在的路徑
pos=realPath.indexOf(path+clsName);
realPath=realPath.substring(0,pos-1);
//如果類文件被打包到JAR等文件中時,去掉對應的JAR等打包文件名
if(realPath.endsWith("!"))
realPath=realPath.substring(0,realPath.lastIndexOf("/"));
/*------------------------------------------------------------
ClassLoader的getResource方法使用了utf-8對路徑信息進行了編碼,當路徑
中存在中文和空格時,他會對這些字符進行轉換,這樣,得到的往往不是我們想要
的真實路徑,在此,調用了URLDecoder的decode方法進行解碼,以便得到原始的
中文及空格路徑
-------------------------------------------------------------*/
try{
realPath=java.net.URLDecoder.decode(realPath,"utf-8");
}catch(Exception e){throw new RuntimeException(e);}
return realPath;
}//getAppPath定義結束
//-----------------------------------------------------------------
[/code]
該方法既可以用於JAR或WAR文件,也可以用於非JAR文件。但要注意以下2點:
[list=1]
[*]不要傳遞系統的類,作爲getAppPath的參數,如java.lang.String.class,當然,也不要傳遞那些已經位於JDK中的那些類,比如xml相關的一些類等等。
[*]要傳遞應該是程序中主要的運行類,不要傳遞程序中的支持類庫中的類文件,也就是那些第三方的類庫中的類文件,否則得到的將是那些類庫的位置。
[/list]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章