在java中獲取資源
我們通常要做的一件事就是在開發(fā)java程序時獲取資源。那資源是什么?說到底,在電腦里就是一堆數據。只是這些數據對我們的java程序有多種表現形式,通常有File,URL,InputStream等。而且僅僅是文檔這個項目就有很多種:環(huán)境變量,java類文檔,jps文檔,照片,照片,css、js文檔等等。面對眾多的資源,當我們設計一個讀取資源的界面時,我們需要為不同形式的資源提供方法,這導致我們的界面仍然與實際的資源方法聯系在一起,并且沒有完全抽象。另外,資源在java系統中的存儲位置也各不相同。有的存儲在classpath中,有的存儲在文件系統中,有的存儲在web應用中。而且java程序在不同位置的資源中獲取這些資源的方法也不同。
A、在classpath中獲取資源:
URL url = this.getClass().getResource("resource_name");
URL url = this.getClass().getClassLoader().getResource("resource_name");
URL url = Thread.currentThread().getContextClassLoader().getResource("resource_name");
那為什么在jdk中又帶來了三種獲取classpath下資源的方法呢?這些都有一些來源。
在第一行代碼中,使用Class類的例子來獲取,第二行代碼是通過載入當前類的classloader來獲取的。看看jdk中的源代碼,你會發(fā)現class類的例子最終被委托載入他的classloader來獲取資源。
public java.net.URL getResource(String name) {
name = resolveName(name);
ClassLoader cl = GetClassLoader0();
if (cl==null) {
// A system class.
return ClassLoader.getSystemResource(name);
}
return cl.getResource(name);
}
根據上述代碼可以看出,對于資源的載入,沒有像類載入所用的雙親委托機制。但當當前類的classloader不是null時,首先將資源從當前類的classloader中載入。而且只有當當前類的classloader是null時,system才是 在classloader中載入資源。因此,我們可以方便地定制配置類來覆蓋一些默認配置。當然,如果在j2se應用中沒有特別定制classloader,我們自己寫的類都是system。 載入classloader。到底用class獲取資源和使用classloader獲取資源的區(qū)別是什么?差別就在 resolveName(name)這是一種方法。這兩種形式對資源名稱的表達方式不同。以下是一個簡單的包結構,/表示類路徑的根。
/
|-com.cn.test
|-Test.class
|-test2.txt
|-test1.txt
代碼Java
// 獲得與當前類在同一包下的資源
URL url1 = this.getClass().getResource(test2.txt");
// 獲取com.cn.test包下的資源需要加//
URL url2 = this.getClass().getResource("/com/cn/test/test2.txt");
// 獲取類路徑根下的資源
URL url3 = this.getClass().getClassLoader().getResource(test1.txt");
// 取包com.cn.test包下的資源
URL url4 = this.getClass().getResource("com/cn/test/test2.txt");
裝載類的過程很簡單:找出類所在的位置,并將發(fā)現的Java類字節(jié)碼放入內存中,生成相應的Class目標。Java的類裝載器是專門用來實現這一過程的,JVM不僅僅是一種類裝載器,事實上,如果你愿意的話,你可以讓JVM擁有無數的類裝載器,當然這除了檢測JVM之外,我還不明白其它的用途。你應該已經發(fā)現了這樣一個問題。類裝載器本身也是一個類,也需要裝載到內存中。誰來裝載這些類裝載器?總有根吧?是的,確實有這樣一個根,那就是Bootstrapp,神龍見頭不見尾。 ClassLoader. 為什么說它的龍看不到尾巴,因為你根本抓不住Java代碼里的一點尾巴,雖然你可以一直感受到它的存在,但是它本身就是C,因為java運行環(huán)境所需的所有類庫都是裝載的。 編寫程序,可獨立運行,可以算是JVM的運行起點,優(yōu)秀吧。當Bootstrap完成其任務后,它將生成一個AppClassLoader(實際上,在此之前,該系統還將使用擴展裝載器ExtClassLoader,它用于裝載Java運行環(huán)境擴展包中的類),這種裝載器是經常使用的,可以調用ClassLoader。.getSystemClassLoader() 來獲取,假設我們沒有使用類裝載器在系統中的相關操作設置或定制新的類裝載器,那么我們編寫的所有java類都將由其裝載,這是值得尊重的。AppClassLoader搜索類的區(qū)域就是眾所周知的Classpath,也是初學者必須跨越的門檻,是否有一種閃光的感覺,我們根據它的搜索范圍來命名類路徑類裝載器。或者之前假設的情況,當Java中出現一個新的類時,AppClassLoader首先將其傳達給其父類裝載器,即Extion。 ClassLoader,問問它能不能裝載這樣的東西,如果可以的話,那么AppClassLoader就不會做這份工作了,同樣Extion。 在裝載ClassLoader時,還會先問它的父類裝載器。不難發(fā)現,類裝載器其實是一個樹形的框架圖。每個類裝載器都有自己的父親。類裝載器在裝載類裝載時,總是先裝載自己的父類裝載器(對長輩多么尊重)。如果父類裝載器不能裝載這種裝載器,它會自己裝載。如果它不能裝載,那么對不起,它會喊:Exception,class not found。當NoClassDefFoundException因直接類路徑裝載器裝載類失敗而拋出的時候,就是NoClassDefFoundException。如采用自定義的類裝載器loadClass方法或ClassLoaderfindSystemClass方法裝載類,如果您不刻意改變,則拋出ClassNotFoundException。
假如一個類是通過bootstrapp 如果我們輸入,那么如果我們通過這個類別獲得classloader,一些jdk的實現將返回null,例如,我使用它。 new Object().getClass().getClassLoader(),將回到null,這樣,NullPointer異常就會出現在上面的代碼中。.所以為了保險起見,我們最好還是用自己寫的類來獲得classloader("this.getClass().getClassLoader()"),這樣就不會有問題了。
B、在文件系統中獲取資源
代碼Java
// 1、獲得File目標
File file = new File("test.txt");
// 2、字節(jié)流以獲得File對象。
InputStream in = new FileInputStream(file);
值得注意的是,File的構造函數File(String name) name參數可以是相對路徑和絕對路徑。與System相比,相對路徑是.getProperties("user.dir")的。
C、在web應用中獲取資源
servletContext.getResourceAsStream(resource_name);
resource_names是相對于webroot的路徑表示。例如獲取webbes.xml,resource_name表示為“//”WEB-INF/web.xml"
面臨上述各種資源的表現形式和存儲位置,java難道沒有提供統一的處理方法嗎?是的,java.net.URL。
就名字而言 URL(Uniform Resource Locator) 統一資源定位儀??雌饋矸浅:?,非常強大。但是很多時候使用它并不能定位我們需要的資源。
第一,其jdk系統中的URL可以瀏覽的協議非常有限(完全可以擴展,但是很麻煩);http是常用的,file,ftp等等。在classpath和servletContext中,沒有提供獲取資源的方法。
另外,它沒有提供方法來判斷資源是否存在。每一次,只有當我們真正獲得資源時,拋出異常才會知道資源無法獲得。
第二,URL這一類的職責沒有明確劃分,既用來表示資源可以用來獲取資源。
相對路徑在jsp和class文檔中有所不同。根目錄是jsp中的WebRoot。 根目錄是WebRoot//class文檔。WEB-INF/classes 當然你也可以使用System.getProperty("user.dir")得到你所有的工程路徑。
1.在jsp中獲取路徑:
以項目名稱TEST為例
(1)獲得包括工程名稱在內的當前頁面全路徑:
request.getRequestURI()
結果:/TEST/test.jsp
(2)獲得工程名稱:
request.getContextPath()
結果:/TEST
獲得當前頁面所在目錄下的全名:
request.getServletPath()
結果:如果頁面在jsp目錄下 /TEST/jsp/test.jsp
(4)獲取頁面所在服務器的全部路徑:
application.getRealPath("test.jsp")
結果:D:\resin\webapps\TEST\test.jsp
(5)獲取頁面所在服務器的正確路徑:
absPath=new java.io.File(application.getRealPath(request.getRequestURI())).getParent();
結果:D:\resin\webapps\TEST
在類別中獲得路徑:
(1)類的盡對路徑:
Class.class.getClass().getResource("/").getPath()
(2)獲得工程的路徑:
System.getProperty("user.dir")
結果:D:\TEST
獲取Servlet中的路徑:
(1)獲得工程目錄:
request.getSession().getServletContext().getRealPath(")//參數可以具體到包名。
結果:E:\Tomcat\webapps\TEST
(2)獲取IE地址欄地址:
request.getRequestURL()
結果:http://localhost:8080/TEST/test
(3)獲得相對地址:
request.getRequestURI()
結果:/TEST/test
本文僅代表作者觀點,版權歸原創(chuàng)者所有,如需轉載請在文中注明來源及作者名字。
免責聲明:本文系轉載編輯文章,僅作分享之用。如分享內容、圖片侵犯到您的版權或非授權發(fā)布,請及時與我們聯系進行審核處理或刪除,您可以發(fā)送材料至郵箱:service@tojoy.com