關(guān)于Java項(xiàng)目讀取resources資源文件路徑的那點(diǎn)事
Java項(xiàng)目讀取resources資源文件路徑的那點(diǎn)事
在Java程序中讀取resources資源下的文件,由于對Java結(jié)構(gòu)了解不透徹,遇到很多坑。
正常在Java工程中讀取某路徑下的文件時(shí),可以采用絕對路徑和相對路徑,絕對路徑?jīng)]什么好說的,相對路徑,即相對于當(dāng)前類的路徑。
在本地工程和服務(wù)器中讀取文件的方式有所不同,以下圖配置文件為例:

一、本地讀取資源文件
Java類中需要讀取properties中的配置文件,可以采用文件(File)方式進(jìn)行讀?。?/p>
File file = new File("src/main/resources/properties/test.properties");
InputStream in = new FileInputStream(file);注意:當(dāng)在IDEA中運(yùn)行(不部署在服務(wù)器上),可以讀取到該文件;
原因:JavaWeb項(xiàng)目部署服務(wù)器中,會將項(xiàng)目打包成Jar包或者war包,此時(shí)就不會存在 src/main/resources 目錄,JVM會在編譯項(xiàng)目時(shí),主動將 java文件編譯成 class文件 和 resources 下的靜態(tài)文件放在 target/classes目錄下;
理解:Java文件只有編譯成 class文件才會被JVM執(zhí)行,本地執(zhí)行時(shí)會,當(dāng)前項(xiàng)目即為Java進(jìn)程的工作空間,雖然class文件在target/classes目錄下,但是target/classes不是class文件運(yùn)行的目錄,只是存放的目錄,運(yùn)行目錄還是在IDEA的模塊下,所以運(yùn)行時(shí)會找到 src/main/resources 資源文件!
二、服務(wù)器(Tomcat)讀取資源文件
當(dāng)工程部署到Tomcat中時(shí),按照上邊方式,則會拋出異常:FileNotFoundException。
原因:Java工程打包部署到Tomcat中時(shí),properties的路徑變到頂層(classes下),這是由Maven工程結(jié)構(gòu)決定的。
由Maven構(gòu)建的web工程,主代碼放在src/main/java路徑下,資源放在src/main/resources路徑下,當(dāng)構(gòu)建jar包 或 war包時(shí),JVM虛擬機(jī)會自動編譯java文件為class文件存放在 target/classes目錄下,resource資源下的文件會原封不動的拷貝一份到 target/classes 目錄下:

方式一:此時(shí)讀取資源文件時(shí),采用流(Stream)的方式讀取,并通過JDK中Properties類加載
可以方便的獲取到配置文件中的信息:
InputStream in = this.getClass().getResourceAsStream("/properties/test.properties");
Properties properties = new Properties();
properties.load(in);
properties.getProperty("name");重點(diǎn)理解:class.getResourceAStream() 與 class.getClassLoader().getResorceAsStream() 的區(qū)別

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 可以加載資源文件,是因?yàn)?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);
}理由:??之所以這樣做無疑還是方便客戶端的調(diào)用,省的每次獲取ClassLoader才能加載資源文件的麻煩!
2).class 是獲取當(dāng)前類的 class 對象,getClassLoader()是獲取當(dāng)前的類加載器,什么是類加載器?
簡單點(diǎn)說,就是用來加載java類的,類加載器就是負(fù)責(zé)把class文件加載進(jìn)內(nèi)存中,并創(chuàng)建一個(gè)java.lang.Class類的一個(gè)實(shí)例,也就是class對象,并且每個(gè)類的類加載器都不相同,getResourceAsStream(path)是用來獲取資源的,因?yàn)檫@是ClassLoader(類加載器)獲取資源,而類加載器默認(rèn)是從 classPath 下獲取資源的,因?yàn)檫@下面有class文件。
所以這段代碼總的意思是通過類加載器在 classPath 目錄下獲取資源,并且是以流的形式。
我們知道在Java中所有的類都是通過加載器加載到虛擬機(jī)中的,而且類加載器之間存在父子關(guān)系,就是子知道父,父不知道子,這樣不同的子加載的類型之間是無法訪問的(雖然它們都被放在方法區(qū)中),所以在這里通過當(dāng)前類的加載器來加載資源也就是保證是和類類型是同一個(gè)加載器加載的。
三、class.getClassLoader().getResourceAsStream() 和 class.getResouceAsStream() 的區(qū)別
a)class.getClassLoader().getResourceAsStream(Stringname)默認(rèn)從classpath中找文件(文件放在resources目錄下),name不能帶"/",否則會拋空指針。采用相對路徑, "/"就相當(dāng)于當(dāng)前進(jìn)程的根目錄,即項(xiàng)目根目錄;
inStream = PropertiesTest.class.getClassLoader().getResourceAsStream("com/test/demo/test.properties");b)class.getResourceAsStream(String name) 是采用絕對路徑,絕對路徑是相對于 classpath 根目錄的路徑,"/" 就代表著 classpath,所以 name 屬性需要前面加上 "/";
inStream = PropertiesTest.class.getResourceAsStream("/com/test/demo/test.properties")方式二:采用Spring注解
如果工程中使用Spring,可以通過注解的方式獲取配置信息,但需要將配置文件放到Spring配置文件中掃描后,才能將配置信息放入上下文。
<context:component-scan base-package="com.xxxx.service"/> <context:property-placeholder location="classpath:properties/xxx.properties" ignore-unresolvable="true"/>
然后在程序中可以使用 @Value進(jìn)行獲取properties文件中的屬性值,如下:
@Value("${xxxt.server}")
private static String serverUrl;方式三:采用Spring配置
也可以在Spring配置文件中讀取屬性值,賦予類成員變量
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:properties/xxx.properties"/>
</bean>
<bean id="service" class="com.xxxx.service.ServiceImpl"> <property name="serverUrl" value="${xxxt.server}" />
</bean>
</beans>重點(diǎn):SpringBoot項(xiàng)目啟動后,動態(tài)的讀取類路徑下文件數(shù)據(jù)
InputStream inputStream = EncryptUtil.class.getResourceAsStream("/HelloServiceEncryptFile.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line = reader.readLine();
// 獲取類路徑下的文件路徑
File path = new File(ResourceUtils.getURL("classpath:").getPath());
if (!path.exists()) {
path = new File("");
}
log.info("path = {}", path.getAbsolutePath());
File upload = new File(path.getAbsolutePath(), "com/study/service");
if (!upload.exists()) {
upload.mkdirs();
}
FileOutputStream fos = new FileOutputStream(upload.getAbsolutePath() + File.separator + "hello.txt");
IoUtil.copy(inputStream, fos);
fos.close();
inputStream.close();注意:此時(shí)我想讀取 jar 包中根路徑下的 HelloServiceEncryptFile.txt 文件,然后重新寫入到根路徑下的 com.study/service 路徑下!
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解用JWT對SpringCloud進(jìn)行認(rèn)證和鑒權(quán)
這篇文章主要介紹了詳解用JWT對SpringCloud進(jìn)行認(rèn)證和鑒權(quán),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03
SpringBoot創(chuàng)建多模塊項(xiàng)目的全過程記錄
這篇文章主要給大家介紹了關(guān)于SpringBoot創(chuàng)建多模塊項(xiàng)目的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01
Spring中容器的創(chuàng)建流程詳細(xì)解讀
這篇文章主要介紹了Spring中容器的創(chuàng)建流程詳細(xì)解讀,Spring?框架其本質(zhì)是作為一個(gè)容器,提供給應(yīng)用程序需要的對象,了解容器的誕生過程,有助于我們理解?Spring?框架,也便于我們“插手”這個(gè)過程,需要的朋友可以參考下2023-10-10
Java IO創(chuàng)建目錄和文件實(shí)例代碼
本篇文章給大家分享了Java IO創(chuàng)建目錄和文件的實(shí)例代碼,過程很簡單,大家可以測試參考下。2018-02-02
SpringBoot如何讀取xml配置bean(@ImportResource)
這篇文章主要介紹了SpringBoot如何讀取xml配置bean(@ImportResource),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01

