絕對地址與相對地址
阿新 • • 發佈:2019-01-30
- Java的路徑問題,非常難搞。最近的工作涉及到建立和讀取檔案的工作,這裡我就給大家徹底得解決Java路徑問 題。
- 我編寫了一個方法,比 ClassLoader.getResource(String 相對路徑)方法的能力更強。它可以接受“../”這樣的引數,允許我們用相對路徑來定位 classpath外面的資源。這樣,我們就可以使用相對於classpath的路徑,定位所有位置的資源!
- Java路徑
- Java中使用的路徑,分為兩 種:絕對路徑和相對路徑。具體而言,又分為四種:
- 一、URI形式的絕對資源路徑
- 如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/aaa.b
- URL是URI的特例。URL的字首/協議,必須是Java認識的。URL可以開啟資源,而URI則不行。
- URL和URI物件可以互相轉換,使用各自的toURI(),toURL()方法即可!
- 二、本地系統的絕對路徑
- D:/java/eclipse32/workspace/jbpmtest3/bin/aaa.b
- Java.io包中的類,需要使用這種形式的引數。
- 但是,它們一般也提供了URI型別的引數,而URI型別的引數,接受的是URI樣式的String。因此,通過URI轉換,還是可以把URI樣式的絕對 路徑用在java.io包中的類中。
- 三、相對 於classpath的相對路徑
- 如:相對 於
- file:/D:/java /eclipse32/workspace/jbpmtest3/bin/這個路徑的相對路徑。其中,bin是本專案的classpath。所有的 Java原始檔編譯後的.class 檔案複製到這個目錄中。
- 四、相對於當前使用者目錄的相對路徑
- 就是相對 於System.getProperty("user.dir" )返回的路 徑。
- 對於一般專案,這是專案的 根路徑。對於JavaEE伺服器,這可能是伺服器的某個路徑。這個並沒有統一的規範!
- 所以,絕對不要使用“相對於當前使用者目錄的相對路徑”。然而:
- 預設情況下,java.io 包中的類總是根據當前使用者目錄來分析相對路徑名。此目錄由系統屬性 user.dir 指定,通常是 Java 虛擬機器的 呼叫目錄。
- 這就是說,在使用java.io包 中的類時,最好不要使用相對路徑。否則,雖然在J2SE應用程式中可能還算正常,但是到了J2EE程式中,一定會出問題!而且這個路徑,在不同的伺服器中 都是不同的!
- 相對路徑最佳實踐
- 推薦使用相對於當前classpath的相對路徑
- 因此,我們在使用相對路徑時,應當使用相對於當前classpath的相對路徑。
- ClassLoader類的getResource(String name),getResourceAsStream(String name)等 方法,使用相對於當前專案的classpath的相對路徑來查詢資源。
- 讀取屬性檔案常用到的ResourceBundle類的getBundle(String path)也是如此。
- 通過檢視ClassLoader類及其相關類的原始碼,我發現,它實際上還是使用了URI形式的絕對路徑。通過得到當前classpath的URI形式 的絕對路徑,構建了相對路徑的URI形式的絕對路徑。(這個實際上是猜想,因為JDK內部呼叫了SUN的原始碼,而這些程式碼不屬於JDK,不是開源 的。)
- 相對路徑本質上還是絕對路徑
- 因此,歸根結底,Java本質上只能使用絕對路徑來尋找資源。所有的相對路徑尋找資源的方法,都不過是一些便利方法。不過是API在底層幫助我們構建了 絕對路徑,從而找到資源的!
- 得到 classpath和當前類的絕對路徑的一些方法
- 下面是一些得到classpath和當前類的絕對路徑的一些方法。你可能需要使用其中的一些方法來得到你需要的資源的絕對路徑。
- 1 .FileTest. class .getResource( "" )
- 得到的是當前類FileTest.class 檔案的URI目錄。不包括自 己!
- 如:file:/D: /java/eclipse32/workspace/jbpmtest3/bin/com/test/
- 2 .FileTest. class .getResource( "/" )
- 得到的是當前的classpath的絕對URI路徑。
- 如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/
- 3 .Thread.currentThread().getContextClassLoader().getResource( "" )
- 得到的也是當前ClassPath的絕對URI路徑。
- 如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/
- 4 .FileTest. class .getClassLoader().getResource( "" )
- 得到的也是當前ClassPath的絕對URI路徑。
- 如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/
- 5 .ClassLoader.getSystemResource( "" )
- 得到的也是當前ClassPath的絕對URI路徑。
- 如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/
- 我推薦使用Thread.currentThread().getContextClassLoader().getResource("" )來得到當前的classpath的絕對路徑的URI表示法。
- Web應用程式中資源的定址
- 上文中說過,當 前使用者目錄,即相對於System.getProperty("user.dir" ) 返回的路徑。
- 對於JavaEE 伺服器,這可能是伺服器的某個路徑,這個並沒有統一的規範!
- 而不是我們釋出的Web應用程式的根目錄!
- 這樣,在Web應用程式中,我們絕對不能使用相對於當前使用者目錄的相對路徑。
- 在Web應用程式中,我們一般通過ServletContext.getRealPath("/" ) 方法得到Web應用程式的根目錄的絕對路徑。
- 這樣,我們只需要提供相對於Web應用程式根目錄的路徑,就可以構建出定位資源的絕對路徑。
- 這是我們開發Web應用程式時一般所採取的策略。
- Web應用程式,可以作為Web應用程式進行釋出和執行。但是,我們也常常會以JavaSE的方式來執行Web應用程式的某個類的main方法。或者, 使用JUnit測試。這都需要使用JavaSE的方式來執行。
- 這樣,我們就無法使用ServletContext.getRealPath("/" ) 方法得到Web應用程式的根目錄的絕對路徑。
- 而JDK提供的ClassLoader類,它的 getResource(String name),getResourceAsStream(String name)等方法,使用相對於當前專案的 classpath的相對路徑來查詢資源。
- 讀 取屬性檔案常用到的ResourceBundle類的getBundle(String path)也是如此。
- 它們都只能使用相對路徑來讀取classpath下的資源,無法定位到classpath外面的資源。
- Classpath外配置檔案讀取問題
- 如, 我們使用測試驅動開發的方法,開發Spring、Hibernate、iBatis等使用配置檔案的Web應用程式,就會遇到問題。
- 儘管Spring自己提供了FileSystem(也就是相對於user,dir目錄)來讀取Web配置檔案的方法,但是終究不是很方便。而且與Web 程式中的程式碼使用方式不一致!
- 至於 Hibernate,iBatis就更麻煩了!只有把配置檔案移到classpath下,否則根本不可能使用測試驅動開發!
- 這怎麼辦?
- 通用的相對路徑解決辦法
- 面對這個問題,我決定編寫一個助手類ClassLoaderUtil,提供一個便利方法[public static URL getExtendResource(String relativePath)]。 在Web應用程式等一切Java程式中,需要定位classpath外的資源時,都使用這個助手類的便利方法,而不使用Web應用程式特有的 ServletContext.getRealPath( "/" ) 方法來定位資源。
- 利用 classpath的絕對路徑,定位所有資源
- 這個便利方法的實現原理,就是“利用classpath的絕對路徑,定位所有資源”。
- ClassLoader類的getResource("" )方法能夠得到當前 classpath的絕對路徑,這是所有Java程式都擁有的能力,具有最大的適應性!
- 而 目前的JDK提供的ClassLoader類的getResource(String 相對路徑)方法,只能接受一般的相對路徑。這樣,使用 ClassLoader類的getResource(String 相對路徑)方法就只能定位到classpath下的資源。
- 如果,它能夠接受“../”這樣的引數,允許我們用相對路徑來定位classpath外面的資源,那麼我們就可以定位位置的資源!
- 當然,我無法修改ClassLoader類的這個方法,於是,我編寫了一個助手類ClassLoaderUtil類,提供了[public static URL getExtendResource(String relativePath)] 這個方法。它能夠接受帶有“../”符號的相對路徑,實現了自由尋找資源的功能。
- 通過相對classpath路徑實現自由尋找資源的助手類的原始碼:
- import java.io.IOException;
- import java.io.InputStream;
- import java.net.MalformedURLException;
- import java.net.URL;
- import java.util.Properties;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- /**
- *@author 沈東良[email protected]
- *Nov29,2006 10:34:34AM
- *用來載入類,classpath下的資原始檔,屬性檔案等。
- *getExtendResource(StringrelativePath)方法,可以使用../符號來載入 classpath外部的資源。
- */
- publicclass ClassLoaderUtil {
- privatestatic Log log=LogFactory.getLog(ClassLoaderUtil.class );
- /**
- *Thread.currentThread().getContextClassLoader().getResource("")
- */
- /**
- *載入Java類。 使用全限定類名
- *@paramclassName
- *@return
- */
- publicstatic Class loadClass(String className) {
- try {
- return getClassLoader().loadClass(className);
- } catch (ClassNotFoundException e) {
- thrownew RuntimeException("class not found '" +className+ "'" , e);
- }
- }
- /**
- *得到類載入器
- *@return
- */
- publicstatic ClassLoader getClassLoader() {
- return ClassLoaderUtil. class .getClassLoader();
- }
- /**
- *提供相對於classpath的資源路徑,返回檔案的輸入流
- *@paramrelativePath必須傳遞資源的相對路徑。是相對於classpath的路徑。如果需要查詢 classpath外部的資源,需要使用 ../來查詢
- *@return 檔案輸入流
- *@throwsIOException
- *@throwsMalformedURLException
- */
- publicstatic InputStream getStream(String relativePath) throws MalformedURLException, IOException {
- if (!relativePath.contains( "../" )){
- return getClassLoader().getResourceAsStream(relativePath);
- }else {
- return ClassLoaderUtil.getStreamByExtendResource(relativePath);
- }
- }
- /**
- *
- *@paramurl
- *@return
- *@throwsIOException
- */
- publicstatic InputStream getStream(URL url) throws IOException{
- if (url!= null ){
- return url.openStream();
- }else {
- returnnull;
- }
- }
- /**
- *
- *@paramrelativePath必須傳遞資源的相對路徑。是相對於classpath的路徑。如果需要查詢classpath外部的資源,需要使 用 ../來查詢
- *@return
- *@throwsMalformedURLException
- *@throwsIOException
- */
- publicstatic InputStream getStreamByExtendResource(String relativePath) throws MalformedURLException, IOException{
- return ClassLoaderUtil.getStream(ClassLoaderUtil.getExtendResource(relativePath));
- }
- /**
- *提供相對於classpath的資源路徑,返回屬性物件,它是一個散列表
- *@paramresource
- *@return
- */
- publicstatic Properties getProperties(String resource) {
- Properties properties = new Properties();
- try {
- properties.load(getStream(resource));
- } catch (IOException e) {
- thrownew RuntimeException("couldn't load properties file '" +resource+ "'" , e);
- }
- return properties;
- }
- /**
- *得到本Class所在的ClassLoader的Classpat的絕對路徑。
- *URL形式的
- *@return
- */
- publicstatic String getAbsolutePathOfClassLoaderClassPath(){
- ClassLoaderUtil.log.info(ClassLoaderUtil.getClassLoader().getResource("" ).toString());
- return ClassLoaderUtil.getClassLoader().getResource( "" ).toString();
- }
- /**
- *
- *@paramrelativePath 必須傳遞資源的相對路徑。是相對於classpath的路徑。如果需要查詢classpath外部的資源,需要 使 用../來查詢
- *@return資 源的絕對URL
- *@throwsMalformedURLException
- */
- publicstatic URL getExtendResource(String relativePath) throws MalformedURLException{
- ClassLoaderUtil.log.info("傳入的相對路徑:" +relativePath) ;
- //ClassLoaderUtil.log.info(Integer.valueOf(relativePath.indexOf("../"))) ;
- if (!relativePath.contains( "../" )){
- return ClassLoaderUtil.getResource(relativePath);
- }
- String classPathAbsolutePath=ClassLoaderUtil.getAbsolutePathOfClassLoaderClassPath();
- if (relativePath.substring( 0 , 1 ).equals( "/" )){
- relativePath=relativePath.substring(1 );
- }
- ClassLoaderUtil.log.info(Integer.valueOf(relativePath.lastIndexOf("../" ))) ;
- String wildcardString=relativePath.substring(0 ,relativePath.lastIndexOf( "../" )+ 3 );
- relativePath=relativePath.substring(relativePath.lastIndexOf("../" )+ 3 );
- int containSum=ClassLoaderUtil.containSum(wildcardString, "../" );
- classPathAbsolutePath= ClassLoaderUtil.cutLastString(classPathAbsolutePath, "/" , containSum);
- String resourceAbsolutePath=classPathAbsolutePath+relativePath;
- ClassLoaderUtil.log.info("絕對路徑:" +resourceAbsolutePath) ;
- URL resourceAbsoluteURL=new URL(resourceAbsolutePath);
- return resourceAbsoluteURL;
- }
- /**
- *
- *@paramsource
- *@paramdest
- *@return
- */
- privatestaticint containSum(String source,String dest){
- int containSum= 0 ;
- int destLength=dest.length();
- while (source.contains(dest)){
- containSum=containSum+1 ;
- source=source.substring(destLength);
- }
- return containSum;
- }
- /**
- *
- *@paramsource
- *@paramdest
- *@paramnum
- *@return
- */
- privatestatic String cutLastString(String source,String dest,int num){
- // String cutSource=null;
- for ( int i= 0 ;i<num;i++){
- source=source.substring(0 , source.lastIndexOf(dest, source.length()- 2 )+ 1 );
- }
- return source;
- }
- /**
- *
- *@paramresource
- *@return
- */
- publicstatic URL getResource(String resource){
- ClassLoaderUtil.log.info("傳入的相對於classpath的路徑:" +resource) ;
- return ClassLoaderUtil.getClassLoader().getResource(resource);
- }
- /**
- *@paramargs
- *@throwsMalformedURLException
- */
- publicstaticvoid main(String[] args) throws MalformedURLException {
- //ClassLoaderUtil.getExtendResource("../spring/dao.xml");
- //ClassLoaderUtil.getExtendResource("../../../src/log4j.properties");
- ClassLoaderUtil.getExtendResource("log4j.properties" );
- System.out.println(ClassLoaderUtil.getClassLoader().getResource("log4j.properties" ).toString());
- }
- }
- 後記
- ClassLoaderUtil類的public static URL getExtendResource(String relativePath), 雖然很簡單,但是確實可以解決大問題。
- 不過這個方法還是比較簡陋的。我還想在未來有空時,進一步增強它的能力。比如,增加Ant風格的匹配符。用**代表多個目錄,*代表多個字元,?代表一 個字元。達到Spring那樣的能力,一次返回多個資源的URL,進一步方便大家開發。
- 總結:
- 1 .儘量不要使用相對於System.getProperty( "user.dir" )當前使用者目錄的相對路徑。
- 2 .儘量使用URI形式的絕對路徑資源。它可以很容易的轉變為 URI,URL,File物件。
- 3 .儘量使用相對classpath的相對路徑。不要使用絕對路徑。使用上面 ClassLoaderUtil類的 public static URL getExtendResource(String relativePath) 方法已經能夠使用相對於classpath的相對路徑定位所有位置的資源。
- 4 .絕對不要使用硬編碼的絕對路徑。因為,我們完全可以使用 ClassLoader類的getResource( "" )方法得 到當前classpath的絕對路徑。
- 使用硬編碼的絕對路徑是完全沒有必要的!它一定 會讓你死的很難看!程式將無法移植!
- 如果你一 定要指定一個絕對路徑,那麼使用配置檔案,也比硬編碼要好得多!
- 當然,我還是推薦你使用程式得到classpath的絕對路徑來拼資源的絕對路徑!
- 1 .如何獲得當前檔案路徑
- 常 用:
- 字串型別:System.getProperty("user.dir" );
- 綜 合:
- package com.zcjl.test.base;
- import java.io.File;
- public class Test {
- public static void main(String[] args) throws Exception {
- System.out.println(
- Thread.currentThread().getContextClassLoader().getResource("" ));
- System.out.println(Test.class .getClassLoader().getResource( "" ));
- System.out.println(ClassLoader.getSystemResource("" ));
- System.out.println(Test.class .getResource( "" ));
- System.out.println(Test.class .getResource( "/" ));
- System.out.println(new File( "" ).getAbsolutePath());
- System.out.println(System.getProperty("user.dir" ));
- }
- }
- file:/E:/workSpace/javaTest/target/classes/
- file:/E:/workSpace/javaTest/target/classes/
- file:/E:/workSpace/javaTest/target/classes/
- file:/E:/workSpace/javaTest/target/classes/javaAPI/
- file:/E:/workSpace/javaTest/target/classes/
- E:/workSpace/javaTest
- E:/workSpace/javaTest
- 2 .Web服務中
- (1 ).Weblogic
- WebApplication 的系統檔案根目錄是你的weblogic安裝所在根目錄。
- 例如:如果你的weblogic安裝在 c:/bea/weblogic700.....
- 那麼,你的檔案根路徑就是c:/.
- 所 以,有兩種方式能夠讓你訪問你的伺服器端的檔案:
- a.使用絕對路徑:
- 比 如將你的引數檔案放在c:/yourconfig/yourconf.properties,
- 直接使 用 new FileInputStream( "/yourconfig/yourconf.properties" );
- b. 使用相對路徑:
- 相對路徑的根目錄就是你的webapplication的根路徑,即WEB-INF的 上一級目錄,將你的引數檔案放在yourwebapp/yourconfig/yourconf.properties,
- 這 樣使用:
- new FileInputStream( "yourconfig/yourconf.properties" );
- 這 兩種方式均可,自己選擇。
- (2 ).Tomcat
- 在 類中輸出System.getProperty("user.dir" );顯示的 是%Tomcat_Home%/bin
- (3 ).Resin
- 不 是你的JSP放的相對路徑,是JSP引擎執行這個JSP編譯成SERVLET
- 的路徑為根.比如用新建 檔案法測試File f = new File( "a.htm" );
- 這個 a.htm在resin的安裝目錄下
- (4 ). 如何讀相對路徑哪?
- 在Java檔案中getResource或 getResourceAsStream均可
- 例:getClass().getResourceAsStream(filePath);//filePath可以是"/filename",這裡的/代表web釋出根路徑下WEB-INF /classes
- 也可以 getClass().getClassLoader().getResourceAsStream(filePath)//filePath不是帶“/”的
- (5 ).獲得檔案真實路徑
- string file_real_path=request.getRealPath("mypath/filename" );
- 通 常使用request.getRealPath("/" );
- 4 .遺留問題
- 目前new FileInputStream()只會使用絕對路徑,相對
- InputStream in1 = new FileInputStream( "abc1.properties" ); // 相對路徑
- InputStream in2 = new FileInputStream( "/abc2.properties" ); // 絕對路徑,E盤下
- InputStream in3 = new FileInputStream( "e://abc3.properties" ); //相對路徑
- 5 .按Java檔案型別分類讀取配置檔案
- 配 置 檔案是應用系統中不可缺少的,可以增加程式的靈活性。java.util.Properties是從jdk1.2 就 有的類,一直到現在都支援load ()方法,jdk1. 4 以後 save(output,string) ->store(output,string)。如果只是單純的讀,根本不存在煩惱的問題。web層可以 通過 Thread.currentThread().getContextClassLoader().
- getResourceAsStream("xx.properties" ) 獲取;
- Application 可以通過new FileInputStream( "xx.properties" );直接在classes一級獲取。關鍵是有時我們需要通過 web修改配置檔案,我們不 能將路徑寫死了。經過測試覺得有以下心得:
- 1 .servlet中讀寫。如果運用Struts 或者Servlet可以直接在初始化引數中 配置,呼叫時根據servlet的getRealPath( "/" ) 獲取真實路徑,再根據String file = this.servlet.getInitParameter( "abc" );獲取相對的WEB-INF的相對路徑。
- 例:
- InputStream input = Thread.currentThread().getContextClassLoader().
- getResourceAsStream("abc.properties" );
- Properties prop = new Properties();
- prop.load(input);
- input.close();
- OutputStream out = new FileOutputStream(path);
- prop.setProperty("abc" , “test");
- prop.store(out, “–test–");
- out.close();
- 2 .直接在jsp中操作,通過jsp內建物件獲取可操作的絕對地址。
- 例:
- // jsp頁面
- String path = pageContext.getServletContext().getRealPath("/" );
- String realPath = path+"/WEB-INF/classes/abc.properties" ;
- //java 程式
- InputStream in = getClass().getClassLoader().getResourceAsStream("abc.properties" ); // abc.properties放在webroot/WEB-INF/classes/目錄下
- prop.load(in);
- in.close();
- OutputStream out = new FileOutputStream(path); // path為通過頁面傳入的路徑
- prop.setProperty("abc" , “abcccccc");
- prop.store(out, “–test–");
- out.close();
- 3 .只通過Java程式操作資原始檔
- InputStream in = new FileInputStream( "abc.properties" ); // 相對路徑,專案下的路徑
- OutputStream out = new FileOutputStream( "abc.properties" );
- Java 的路徑問題,非常難搞。最近的工作涉及到建立和讀取檔案的工作,這裡我就給大家徹底得解決Java路徑問題。
- 我編寫了一個方法,比ClassLoader.getResource(String 相對路徑)方法的能力更強。它可以接受“../”這樣的引數,允 許我們用相對路徑來定位classpath外面的資源。這樣,我們就可以使用相對於classpath的路徑,定位所有位置的資源!
- Java路徑
- Java中使用的路徑,分為兩 種:絕對路徑和相對路徑。具體而言,又分為四種:
- 一、URI形式的絕對資源路徑
- 如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/aaa.b
- URL是URI的特例。URL的字首/協議,必須是Java認識的。URL可以開啟資源,而URI則不行。
- URL和URI物件可以互相轉換,使用各自的toURI(),toURL()方法即可!
- 二、本地系統的絕對路徑
- D:/java/eclipse32/workspace/jbpmtest3/bin/aaa.b
- Java.io包中的類,需要使用這種形式的引數。
- 但是,它們一般也提供了URI型別的引數,而URI型別的引數,接受的是URI樣式的String。因此,通過URI轉換,還是可以把URI樣式的絕對 路徑用在java.io包中的類中。
- 三、相對 於classpath的相對路徑
- 如:相對 於
- file:/D:/java /eclipse32/workspace/jbpmtest3/bin/這個路徑的相對路徑。其中,bin是本專案的classpath。所有的 Java原始檔編譯後的.class 檔案複製到這個目錄中。
- 四、相對於當前使用者目錄的相對路徑
- 就是相對 於System.getProperty("user.dir" )返回的路 徑。
- 對於一般專案,這是專案的 根路徑。對於JavaEE伺服器,這可能是伺服器的某個路徑。這個並沒有統一的規範!
- 所以,絕對不要使用“相對於當前使用者目錄的相對路徑”。然而:
- 預設情況下,java.io 包中的類總是根據當前使用者目錄來分析相對路徑名。此目錄由系統屬性 user.dir 指定,通常是 Java 虛擬機器的 呼叫目錄。
- 這就是說,在使用java.io包 中的類時,最好不要使用相對路徑。否則,雖然在J2SE應用程式中可能還算正常,但是到了J2EE程式中,一定會出問題!而且這個路徑,在不同的伺服器中 都是不同的!
- 相對路徑最佳實踐
- 推薦使用相對於當前classpath的相對路徑
- 因此,我們在使用相對路徑時,應當使用相對於當前classpath的相對路徑。
- ClassLoader類的getResource(String name),getResourceAsStream(String name)等 方法,使用相對於當前專案的classpath的相對路徑來查詢資源。
- 讀取屬性檔案常用到的ResourceBundle類的getBundle(String path)也是如此。
- 通過檢視ClassLoader類及其相關類的原始碼,我發現,它實際上還是使用了URI形式的絕對路徑。通過得到當前classpath的URI形式 的絕對路徑,構建了相對路徑的URI形式的絕對路徑。(這個實際上是猜想,因為JDK內部呼叫了SUN的原始碼,而這些程式碼不屬於JDK,不是開源 的。)
- 相對路徑本質上還是絕對路徑
- 因此,歸根結底,Java本質上只能使用絕對路徑來尋找資源。所有的相對路徑尋找資源的方法,都不過是一些便利方法。不過是API在底層幫助我們構建了 絕對路徑,從而找到資源的!
- 得到 classpath和當前類的絕對路徑的一些方法
- 下面是一些得到classpath和當前類的絕對路徑的一些方法。你可能需要使用其中的一些方法來得到你需要的資源的絕對路徑。
- 1 .FileTest. class .getResource( "" )
- 得到的是當前類FileTest.class 檔案的URI目錄。不包括自 己!
- 如:file:/D: /java/eclipse32/workspace/jbpmtest3/bin/com/test/
- 2 .FileTest. class .getResource( "/" )
- 得到的是當前的classpath的絕對URI路徑。
- 如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/
- 3 .Thread.currentThread().getContextClassLoader().getResource( "" )
- 得到的也是當前ClassPath的絕對URI路徑。
- 如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/
- 4 .FileTest. class .getClassLoader().getResource( "" )
- 得到的也是當前ClassPath的絕對URI路徑。
- 如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/
- 5 .ClassLoader.getSystemResource( "" )
- 得到的也是當前ClassPath的絕對URI路徑。
- 如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/
- 我推薦使用Thread.currentThread().getContextClassLoader().getResource("" )來得到當前的classpath的絕對路徑的URI表示法。
- Web應用程式中資源的定址
- 上文中說過,當 前使用者目錄,即相對於System.getProperty("user.dir" ) 返回的路徑。
- 對於JavaEE 伺服器,這可能是伺服器的某個路徑,這個並沒有統一的規範!
- 而不是我們釋出的Web應用程式的根目錄!
- 這樣,在Web應用程式中,我們絕對不能使用相對於當前使用者目錄的相對路徑。
- 在Web應用程式中,我們一般通過ServletContext.getRealPath("/" ) 方法得到Web應用程式的根目錄的絕對路徑。
- 這樣,我們只需要提供相對於Web應用程式根目錄的路徑,就可以構建出定位資源的絕對路徑。
- 這是我們開發Web應用程式時一般所採取的策略。
- Web應用程式,可以作為Web應用程式進行釋出和執行。但是,我們也常常會以JavaSE的方式來執行Web應用程式的某個類的main方法。或者, 使用JUnit測試。這都需要使用JavaSE的方式來執行。
- 這樣,我們就無法使用ServletContext.getRealPath("/" ) 方法得到Web應用程式的根目錄的絕對路徑。
- 而JDK提供的ClassLoader類,它的 getResource(String name),getResourceAsStream(String name)等方法,使用相對於當前專案的 classpath的相對路徑來查詢資源。
- 讀 取屬性檔案常用到的ResourceBundle類的getBundle(String path)也是如此。
- 它們都只能使用相對路徑來讀取classpath下的資源,無法定位到classpath外面的資源。
- Classpath外配置檔案讀取問題
- 如, 我們使用測試驅動開發的方法,開發Spring、Hibernate、iBatis等使用配置檔案的Web應用程式,就會遇到問題。
- 儘管Spring自己提供了FileSystem(也就是相對於user,dir目錄)來讀取Web配置檔案的方法,但是終究不是很方便。而且與Web 程式中的程式碼使用方式不一致!
- 至於 Hibernate,iBatis就更麻煩了!只有把配置檔案移到classpath下,否則根本不可能使用測試驅動開發!
- 這怎麼辦?
- 通用的相對路徑解決辦法
- 面對這個問題,我決定編寫一個助手類ClassLoaderUtil,提供一個便利方法[public static URL getExtendResource(String relativePath)]。 在Web應用程式等一切Java程式中,需要定位classpath外的資源時,都使用這個助手類的便利方法,而不使用Web應用程式特有的 ServletContext.getRealPath( "/" ) 方法來定位資源。
- 利用 classpath的絕對路徑,定位所有資源
- 這個便利方法的實現原理,就是“利用classpath的絕對路徑,定位所有資源”。
- ClassLoader類的getResource("" )方法能夠得到當前 classpath的絕對路徑,這是所有Java程式都擁有的能力,具有最大的適應性!
- 而 目前的JDK提供的ClassLoader類的getResource(String 相對路徑)方法,只能接受一般的相對路徑。這樣,使用 ClassLoader類的getResource(String 相對路徑)方法就只能定位到classpath下的資源。
- 如果,它能夠接受“../”這樣的引數,允許我們用相對路徑來定位classpath外面的資源,那麼我們就可以定位位置的資源!
- 當然,我無法修改ClassLoader類的這個方法,於是,我編寫了一個助手類ClassLoaderUtil類,提供了[public static URL getExtendResource(String relativePath)] 這個方法。它能夠接受帶有“../”符號的相對路徑,實現了自由尋找資源的功能。
- 通過相對classpath路徑實現自由尋找資源的助手類的原始碼:
- import java.io.IOException;
- import java.io.InputStream;
- import java.net.MalformedURLException;
- import java.net.URL;
- import java.util.Properties;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- /**
- *@author 沈東良[email protected]
- *Nov29,2006 10:34:34AM
- *用來載入類,classpath下的資原始檔,屬性檔案等。
- *getExtendResource(StringrelativePath)方法,可以使用../符號來載入 classpath外部的資源。
- */
- publicclass ClassLoaderUtil {
- privatestatic Log log=LogFactory.getLog(ClassLoaderUtil.class );
- /**
- *Thread.currentThread().getContextClassLoader().getResource("")
- */
- /**
- *載入Java類。 使用全限定類名
- *@paramclassName
- *@return
- */
- publicstatic Class loadClass(String className) {
- try {
- return getClassLoader().loadClass(className);
- } catch (ClassNotFoundException e) {
- thrownew RuntimeException("class not found '" +className+ "'" , e);
- }
- }
- /**
- *得到類載入器
- *@return
- */
- publicstatic ClassLoader getClassLoader() {
- return ClassLoaderUtil. class .getClassLoader();
- }
- /**
- *提供相對於classpath的資源路徑,返回檔案的輸入流
- *@paramrelativePath必須傳遞資源的相對路徑。是相對於classpath的路徑。如果需要查詢 classpath外部的資源,需要使用 ../來查詢
- *@return 檔案輸入流
- *@throwsIOException
- *@throwsMalformedURLException
- */
- publicstatic InputStream getStream(String relativePath) throws MalformedURLException, IOException {
- if (!relativePath.contains( "../" )){
- return getClassLoader().getResourceAsStream(relativePath);
- }else {
- return ClassLoaderUtil.getStreamByExtendResource(relativePath);
- }
- }
- /**
- *
- *@paramurl
- *@return
- *@throwsIOException
- */
- publicstatic InputStream getStream(URL url) throws IOException{
- if (url!= null ){
- return url.openStream();
- }else {
- returnnull;
- }
- }
- /**
- *
- *@paramrelativePath必須傳遞資源的相對路徑。是相對於classpath的路徑。如果需要查詢classpath外部的資源,需要使 用 ../來查詢
- *@return
- *@throwsMalformedURLException
- *@throwsIOException
- */
- publicstatic InputStream getStreamByExtendResource(String relativePath) throws MalformedURLException, IOException{
- return ClassLoaderUtil.getStream(ClassLoaderUtil.getExtendResource(relativePath));
- }
- /**
- *提供相對於classpath的資源路徑,返回屬性物件,它是一個散列表
- *@paramresource
- *@return
- */
- publicstatic Properties getProperties(String resource) {
- Properties properties = new Properties();
- try {
- properties.load(getStream(resource));
- } catch (IOException e) {
- thrownew RuntimeException("couldn't load properties file '" +resource+ "'" , e);
- }
- return properties;
- }
- /**
- *得到本Class所在的ClassLoader的Classpat的絕對路徑。
- *URL形式的
- *@return
- */
- publicstatic String getAbsolutePathOfClassLoaderClassPath(){
- ClassLoaderUtil.log.info(ClassLoaderUtil.getClassLoader().getResource("" ).toString());
- return ClassLoaderUtil.getClassLoader().getResource( "" ).toString();
- }
- /**
- *
- *@paramrelativePath 必須傳遞資源的相對路徑。是相對於classpath的路徑。如果需要查詢classpath外部的資源,需要 使 用../來查詢
- *@return資 源的絕對URL
- *@throwsMalformedURLException
- */
- publicstatic URL getExtendResource(String relativePath) throws MalformedURLException{
- ClassLoaderUtil.log.info("傳入的相對路徑:" +relativePath) ;
- //ClassLoaderUtil.log.info(Integer.valueOf(relativePath.indexOf("../"))) ;
- if (!relativePath.contains( "../" )){
- return ClassLoaderUtil.getResource(relativePath);
- }
- String classPathAbsolutePath=ClassLoaderUtil.getAbsolutePathOfClassLoaderClassPath();
- if (relativePath.substring( 0 , 1 ).equals( "/" )){
- relativePath=relativePath.substring(1 );
- }
- ClassLoaderUtil.log.info(Integer.valueOf(relativePath.lastIndexOf("../" ))) ;
- String wildcardString=relativePath.substring(0 ,relativePath.lastIndexOf( "../" )+ 3 );
- relativePath=relativePath.substring(relativePath.lastIndexOf("../" )+ 3 );
- int containSum=ClassLoaderUtil.containSum(wildcardString, "../" );
- classPathAbsolutePath= ClassLoaderUtil.cutLastString(classPathAbsolutePath, "/" , containSum);
- String resou