獲取Java程序運行的路徑


轉自:http://blog.chinaunix.net/uid-20648927-id-1907273.html

 

對於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程序所在的路徑
   具體代碼如下:
Java代碼 
  1 /**----------------------------------------------------------------------- 
  2 
  3     *getAppPath需要一個當前程序使用的Java類的class屬性參數,它可以返回打包過的 
  4 
  5 
  6  *Java可執行文件(jar,war)所處的系統目錄名或非打包Java程序所處的目錄 
  7 
  8  *@param cls為Class類型 
  9 
 10  *@return 返回值為該類所在的Java程序運行的目錄 
 11 
 12  -------------------------------------------------------------------------*/  
 13 
 14 public static String getAppPath(Class cls){  
 15 
 16     //檢查用戶傳入的參數是否為空  
 17 
 18     if(cls==null)   
 19 
 20      throw new java.lang.IllegalArgumentException("參數不能為空!");  
 21 
 22     ClassLoader loader=cls.getClassLoader();  
 23 
 24     //獲得類的全名,包括包名  
 25 
 26     String clsName=cls.getName()+".class";  
 27 
 28     //獲得傳入參數所在的包  
 29 
 30     Package pack=cls.getPackage();  
 31 
 32     String path="";  
 33 
 34     //如果不是匿名包,將包名轉化為路徑  
 35 
 36     if(pack!=null){  
 37 
 38         String packName=pack.getName();  
 39 
 40        //此處簡單判定是否是Java基礎類庫,防止用戶傳入JDK內置的類庫  
 41 
 42        if(packName.startsWith("java.")||packName.startsWith("javax."))   
 43 
 44           throw new java.lang.IllegalArgumentException("不要傳送系統類!");  
 45 
 46         //在類的名稱中,去掉包名的部分,獲得類的文件名  
 47 
 48         clsName=clsName.substring(packName.length()+1);  
 49 
 50         //判定包名是否是簡單包名,如果是,則直接將包名轉換為路徑,  
 51 
 52         if(packName.indexOf(".")<0) path=packName+"/";  
 53 
 54         else{//否則按照包名的組成部分,將包名轉換為路徑  
 55 
 56             int start=0,end=0;  
 57 
 58             end=packName.indexOf(".");  
 59 
 60             while(end!=-1){  
 61 
 62                 path=path+packName.substring(start,end)+"/";  
 63 
 64                 start=end+1;  
 65 
 66                 end=packName.indexOf(".",start);  
 67 
 68             }  
 69 
 70             path=path+packName.substring(start)+"/";  
 71 
 72         }  
 73 
 74     }  
 75 
 76     //調用ClassLoader的getResource方法,傳入包含路徑信息的類文件名  
 77 
 78     java.net.URL url =loader.getResource(path+clsName);  
 79 
 80     //從URL對象中獲取路徑信息  
 81 
 82     String realPath=url.getPath();  
 83 
 84     //去掉路徑信息中的協議名"file:"  
 85 
 86     int pos=realPath.indexOf("file:");  
 87 
 88     if(pos>-1) realPath=realPath.substring(pos+5);  
 89 
 90     //去掉路徑信息最后包含類文件信息的部分,得到類所在的路徑  
 91 
 92     pos=realPath.indexOf(path+clsName);  
 93 
 94     realPath=realPath.substring(0,pos-1);  
 95 
 96     //如果類文件被打包到JAR等文件中時,去掉對應的JAR等打包文件名  
 97 
 98     if(realPath.endsWith("!"))  
 99 
100         realPath=realPath.substring(0,realPath.lastIndexOf("/"));  
101 
102   /*------------------------------------------------------------ 
103 
104    ClassLoader的getResource方法使用了utf-8對路徑信息進行了編碼,當路徑 
105 
106     中存在中文和空格時,他會對這些字符進行轉換,這樣,得到的往往不是我們想要 
107 
108     的真實路徑,在此,調用了URLDecoder的decode方法進行解碼,以便得到原始的 
109 
110     中文及空格路徑 
111 
112   -------------------------------------------------------------*/  
113 
114   try{  
115 
116     realPath=java.net.URLDecoder.decode(realPath,"utf-8");  
117 
118    }catch(Exception e){throw new RuntimeException(e);}  
119 
120    return realPath;  
121 
122 }//getAppPath定義結束  
123 
124 /-----------------------------------------------------------------  
125   
126     /**-----------------------------------------------------------------------
127      *getAppPath需要一個當前程序使用的Java類的class屬性參數,它可以返回打包過的
128      *Java可執行文件(jar,war)所處的系統目錄名或非打包Java程序所處的目錄
129      *@param cls為Class類型
130      *@return 返回值為該類所在的Java程序運行的目錄
131      -------------------------------------------------------------------------*/
132     public static String getAppPath(Class cls){
133         //檢查用戶傳入的參數是否為空
134         if(cls==null) 
135          throw new java.lang.IllegalArgumentException("參數不能為空!");
136         ClassLoader loader=cls.getClassLoader();
137         //獲得類的全名,包括包名
138         String clsName=cls.getName()+".class";
139         //獲得傳入參數所在的包
140         Package pack=cls.getPackage();
141         String path="";
142         //如果不是匿名包,將包名轉化為路徑
143         if(pack!=null){
144             String packName=pack.getName();
145            //此處簡單判定是否是Java基礎類庫,防止用戶傳入JDK內置的類庫
146            if(packName.startsWith("java.")||packName.startsWith("javax.")) 
147               throw new java.lang.IllegalArgumentException("不要傳送系統類!");
148             //在類的名稱中,去掉包名的部分,獲得類的文件名
149             clsName=clsName.substring(packName.length()+1);
150             //判定包名是否是簡單包名,如果是,則直接將包名轉換為路徑,
151             if(packName.indexOf(".")<0) path=packName+"/";
152             else{//否則按照包名的組成部分,將包名轉換為路徑
153                 int start=0,end=0;
154                 end=packName.indexOf(".");
155                 while(end!=-1){
156                     path=path+packName.substring(start,end)+"/";
157                     start=end+1;
158                     end=packName.indexOf(".",start);
159                 }
160                 path=path+packName.substring(start)+"/";
161             }
162         }
163         //調用ClassLoader的getResource方法,傳入包含路徑信息的類文件名
164         java.net.URL url =loader.getResource(path+clsName);
165         //從URL對象中獲取路徑信息
166         String realPath=url.getPath();
167         //去掉路徑信息中的協議名"file:"
168         int pos=realPath.indexOf("file:");
169         if(pos>-1) realPath=realPath.substring(pos+5);
170         //去掉路徑信息最后包含類文件信息的部分,得到類所在的路徑
171         pos=realPath.indexOf(path+clsName);
172         realPath=realPath.substring(0,pos-1);
173         //如果類文件被打包到JAR等文件中時,去掉對應的JAR等打包文件名
174         if(realPath.endsWith("!"))
175             realPath=realPath.substring(0,realPath.lastIndexOf("/"));
176       /*------------------------------------------------------------
177        ClassLoader的getResource方法使用了utf-8對路徑信息進行了編碼,當路徑
178         中存在中文和空格時,他會對這些字符進行轉換,這樣,得到的往往不是我們想要
179         的真實路徑,在此,調用了URLDecoder的decode方法進行解碼,以便得到原始的
180         中文及空格路徑
181       -------------------------------------------------------------*/
182       try{
183         realPath=java.net.URLDecoder.decode(realPath,"utf-8");
184        }catch(Exception e){throw new RuntimeException(e);}
185        return realPath;
186     }//getAppPath定義結束
187    //-----------------------------------------------------------------

 

該方法既可以用於JAR或WAR文件,也可以用於非JAR文件。但要注意以下2點:
  1. 不要傳遞系統的類,作為getAppPath的參數,如java.lang.String.class,當然,也不要傳遞那些已經位於JDK中的那些類,比如xml相關的一些類等等。
  2. 要傳遞應該是程序中主要的運行類,不要傳遞程序中的支持類庫中的類文件,也就是那些第三方的類庫中的類文件,否則得到的將是那些類庫的位置。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM