關於Java項目讀取resources資源文件路徑


在看此篇博客是建議清楚classpath代表的路徑,getServletContext().getRealPath("/")的含義,idea中項目編譯后的目錄格式,resoures文件夾的編譯

classpath = WEB-INF/classes
getServletContext().getRealPath("/") = 項目絕對路徑

以此項目為例:

 編譯后的目錄為

classpath下的格式為

今天在捯飭web項目的jdbc和druid連接池,遇到一個小問題,早讀去配置文件 properties 時報了FileNotFound錯誤

properties文件在web文件夾下的resoures文件夾中,編譯后在classpath下

當時代碼是這么寫的

FileInputStream stream = new FileInputStream("jdbc.properties");
InputStreamReader inputStreamReader = new InputStreamReader(stream);
Properties properties = new Properties();
.....

當時覺得怪怪的沒多想,直接跑起來然后就報錯了...

第一種改法,拿到項目句對路徑使用ServletContext,打印成功

這個寫法根據上面的路徑很好理解

InputStream stream = new FileInputStream(getServletContext().getRealPath("/") + "resources/jdbc.properties");
InputStreamReader inputStreamReader = new InputStreamReader(stream);
Properties properties = new Properties();
properties.load(inputStreamReader);
properties.forEach((key, value) -> {
  System.out.println(key + "::" + value);
});

第二種寫法,使用   class.getClassLoader().getResourceAsStream() 

InputStream stream = getClass().getClassLoader().getResourceAsStream("/jdbc.properties");
InputStreamReader inputStreamReader = new InputStreamReader(stream);
Properties properties = new Properties();
properties.load(inputStreamReader);

或   class.getResouceAsStream() 

InputStream stream = getClass().getResourceAsStream("jdbc.properties");
... 或 InputStream stream
= getClass().getResourceAsStream("/jdbc.properties");
...

同樣都可以拿到

第三種寫法,使用  ResourceBundle

ResourceBundle jdbc = ResourceBundle.getBundle("jdbc");
driver = jdbc.getString("jdbc.driver");
url = jdbc.getString("jdbc.url");
username = jdbc.getString("jdbc.username");
password = jdbc.getString("jdbc.password");

查閱了相關資料

(1)本地讀取資源文件

 Java類中需要讀取properties中的配置文件,可以采用文件(File)方式進行讀取:

File file = new File("src/main/resources/properties/test.properties");
InputStream in = new FileInputStream(file);

本身普通項目讀取資源文件就是默認從項目根目錄下讀取

注意:當在IDEA中運行(不部署在服務器上),可以讀取到該文件;

  原因:JavaWeb項目部署服務器中,會將項目打包成Jar包或者war包,此時就不會存在 src/main/resources 目錄,JVM會在編譯項目時,主動將 java文件編譯成 class文件 和 resources 下的靜態文件放在 target/classes目錄下;

  理解:Java文件只有編譯成 class文件才會被JVM執行,本地執行時會,當前項目即為Java進程的工作空間,雖然class文件在target/classes目錄下,但是target/classes不是class文件運行的目錄,只是存放的目錄,運行目錄還是在IDEA的模塊下,所以運行時會找到 src/main/resources 資源文件!

(2)服務器(Tomcat)讀取資源文件

當工程部署到Tomcat中時,按照上邊方式,則會拋出異常:FileNotFoundException。原因:Java工程打包部署到Tomcat中時,properties的路徑變到頂層(classes下),這是由Maven工程結構決定的。由Maven構建的web工程,主代碼放在src/main/java路徑下,資源放在src/main/resources路徑下,當構建jar包 或 war包時,JVM虛擬機會自動編譯java文件為class文件存放在 target/classes目錄下,resource資源下的文件會原封不動的拷貝一份到 target/classes 目錄下:

 

 方式一:此時讀取資源文件時,采用流(Stream)的方式讀取,並通過JDK中Properties類加載,可以方便的獲取到配置文件中的信息:

InputStream in = this.getClass().getResourceAsStream("/properties/test.properties");
Properties properties = new Properties();
properties.load(in);
properties.getProperty("name");

重點理解:class.getResourceAStream() 與 class.getClassLoader().getResorceAsStream() 的區別

1) InputStream inStream = PropertiesTest.class.getResourceAsStream("test.properties");
​2) inStream = PropertiesTest.class.getResourceAsStream("/com/test/demo/test.properties");
3) inStream = PropertiesTest.class.getClassLoader().getResourceAsStream("com/test/demo/test.properties");

 1)第一種和第二種方式采用 Class 對象去加載,第三種方式采用 ClassLoader 對象去加載資源文件,之所以 Class 可以加載資源文件,是因為 Class 類封裝的 ClassLoader 的 getResourceAsStream() 方法,從 Class 類中的源碼可以看出:

public InputStream getResourceAsStream(String name) {
        name = resolveName(name);
        ClassLoader cl = getClassLoader0();
        if (cl==null) {
            // A system class.
            return ClassLoader.getSystemResourceAsStream(name);
        }
        return cl.getResourceAsStream(name);
 }

 理由:​​之所以這樣做無疑還是方便客戶端的調用,省的每次獲取ClassLoader才能加載資源文件的麻煩!

 2).class 是獲取當前類的 class 對象,getClassLoader()是獲取當前的類加載器,什么是類加載器?簡單點說,就是用來加載java類的,類加載器就是負責把class文件加載進內存中,並創建一個java.lang.Class類的一個實例,也就是class對象,並且每個類的類加載器都不相同,getResourceAsStream(path)是用來獲取資源的,因為這是ClassLoader(類加載器)獲取資源,而類加載器默認是從 classPath 下獲取資源的,因為這下面有class文件。所以這段代碼總的意思是通過類加載器在 classPath 目錄下獲取資源,並且是以流的形式。我們知道在Java中所有的類都是通過加載器加載到虛擬機中的,而且類加載器之間存在父子關系,就是子知道父,父不知道子,這樣不同的子加載的類型之間是無法訪問的(雖然它們都被放在方法區中),所以在這里通過當前類的加載器來加載資源也就是保證是和類類型是同一個加載器加載的。 

(3)class.getClassLoader().getResourceAsStream() 和 class.getResouceAsStream() 的區別

默認從classpath中找文件(文件放在resources目錄下)name不能帶"/",否則會拋空指針。采用相對路徑, "/"就相當於當前進程的根目錄,即項目根目錄;

a)
class.getClassLoader().getResourceAsStream(String name)
inStream = PropertiesTest.class.getClassLoader().getResourceAsStream("com/test/demo/test.properties");
不加‘ / ’,直接在包的路徑下開始尋找,相當於在已經寫好的path前面加了一句 /包名/path,加‘ / ’,就要從classpath的那一層開始找
b)
class.getResourceAsStream(String name)
inStream = PropertiesTest.class.getResourceAsStream("/com/test/demo/test.properties")

轉載 https://www.cnblogs.com/blogtech/p/11151780.html

 


免責聲明!

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



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