java讀取resources中資源文件路徑以及jar中文件無法讀取如何解決
本文講解"java讀取resources中資源文件路徑以及jar中文件無法讀取怎么解決",希望能夠解決相關(guān)問題。
java讀取resources中資源文件路徑以及jar中文件無法讀取的解決
問題描述
現(xiàn)象
作為一個(gè)剛開始學(xué)習(xí)java的新人,很多東西都是摸著石頭過河,踩坑是常有的事。這不,今天我將maven管理的一個(gè)spring boot的webapp部署到服務(wù)器上,運(yùn)行直接報(bào)錯(cuò)!納尼?。。”镜嘏艿煤煤玫?,一到服務(wù)器就出問題,關(guān)鍵是日志文件中的日志不全,無法馬上定位到問題。好吧,一步一步排除問題吧!
定位
是不是windows與linux的區(qū)別?不是,我在windows上跑了一下打包后的代碼,也出問題了,打包前沒問題,打包后出問題了,包有毒!然后我開放了日志,一步一步調(diào)試(蛋疼啊),最終發(fā)現(xiàn)配置文件沒有加載,路徑出了問題。。。
前言
工程文件結(jié)構(gòu)如下所示,目標(biāo)是讀取resources/python/kafka_producer.py文件
1、本地運(yùn)行讀取資源文件
采用getresource進(jìn)行讀?。?/p>
url?urlpath?=?this.getclass().getresource("/python/kafka_producer.py"); string?execstr?=?string.format("python?%s",?urlpath.getpath().substring(1));
它是在target文件中讀取,這時(shí)文件是我們熟悉的文件。正常讀取,運(yùn)行。
2、讀取jar包中的文件信息
inputstream?is=this.getclass().getresourceasstream("/python/kafka_producer.py"); bufferedreader?br1=new?bufferedreader(new?inputstreamreader(is)); string?s1=""; while((s1=br1.readline())!=null) ???system.out.println(s1);
如果你需要運(yùn)行腳本文件,這時(shí)是不能直接通過路徑獲取的,具體可以看博客點(diǎn)擊。你需要重新將流寫入文件中,在運(yùn)行,當(dāng)然,也可以打war包,不用jar包。如果讀取配置文件有一下兩種方式:
inputstream?in?=?this.getclass().getresourceasstream("/properties/basecom.properties"); properties?properties?=?new?properties(); properties.load(in); properties.getproperty("property_name")
或者
????inputstream?xmlfile?=?this.getclass().getresourceasstream("/jdbctype.xml"); document?document?=?xmlreader.read(xmlfile); element?xmlroot?=?document.getrootelement(); element?childelement?=?xmlroot.element(dbtype); list<element>?childelements?=?childelement.elements(); for?(element?child?:?childelements)?{ }
聊聊java項(xiàng)目讀取resources資源文件路徑那點(diǎn)事?
在java程序中讀取resources資源下的文件,由于對(duì)java結(jié)構(gòu)了解不透徹,遇到很多坑。
正常在java工程中讀取某路徑下的文件時(shí),可以采用絕對(duì)路徑和相對(duì)路徑,絕對(duì)路徑?jīng)]什么好說的,相對(duì)路徑,即相對(duì)于當(dāng)前類的路徑。在本地工程和服務(wù)器中讀取文件的方式有所不同,以下圖配置文件為例:
1、本地讀取資源文件
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ù)器中,會(huì)將項(xiàng)目打包成jar包或者war包,此時(shí)就不會(huì)存在 src/main/resources 目錄,jvm會(huì)在編譯項(xiàng)目時(shí),主動(dòng)將 java文件編譯成 class文件 和 resources 下的靜態(tài)文件放在 target/classes目錄下;
理解:java文件只有編譯成 class文件才會(huì)被jvm執(zhí)行,本地執(zhí)行時(shí)會(huì),當(dāng)前項(xiàng)目即為java進(jìn)程的工作空間,雖然class文件在target/classes目錄下,但是target/classes不是class文件運(yùn)行的目錄,只是存放的目錄,運(yùn)行目錄還是在idea的模塊下,所以運(yùn)行時(shí)會(huì)找到 src/main/resources 資源文件!
2、服務(wù)器(tomcat)讀取資源文件
當(dāng)工程部署到tomcat中時(shí),按照上邊方式,則會(huì)拋出異常: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ī)會(huì)自動(dòng)編譯java文件為class文件存放在 target/classes目錄下,resource資源下的文件會(huì)原封不動(dòng)的拷貝一份到 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 對(duì)象去加載,第三種方式采用 classloader 對(duì)象去加載資源文件,之所以 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 對(duì)象,getclassloader()是獲取當(dāng)前的類加載器,什么是類加載器?簡單點(diǎn)說,就是用來加載java類的,類加載器就是負(fù)責(zé)把class文件加載進(jìn)內(nèi)存中,并創(chuàng)建一個(gè)java.lang.class類的一個(gè)實(shí)例,也就是class對(duì)象,并且每個(gè)類的類加載器都不相同,getresourceasstream(path)是用來獲取資源的,因?yàn)檫@是classloader(類加載器)獲取資源,而類加載器默認(rèn)是從 classpath 下獲取資源的,因?yàn)檫@下面有class文件。
所以這段代碼總的意思是通過類加載器在 classpath 目錄下獲取資源,并且是以流的形式。我們知道在java中所有的類都是通過加載器加載到虛擬機(jī)中的,而且類加載器之間存在父子關(guān)系,就是子知道父,父不知道子,這樣不同的子加載的類型之間是無法訪問的(雖然它們都被放在方法區(qū)中),所以在這里通過當(dāng)前類的加載器來加載資源也就是保證是和類類型是同一個(gè)加載器加載的。
(3)class.getclassloader().getresourceasstream() 和 class.getresouceasstream() 的區(qū)別
a)class.getclassloader().getresourceasstream(stringname)默認(rèn)從classpath中找文件(文件放在resources目錄下),name不能帶"/",否則會(huì)拋空指針。采用相對(duì)路徑, "/"就相當(dāng)于當(dāng)前進(jìn)程的根目錄,即項(xiàng)目根目錄;
instream?=?propertiestest.class.getclassloader().getresourceasstream("com/test/demo/test.properties");
b)class.getresourceasstream(string name) 是采用絕對(duì)路徑,絕對(duì)路徑是相對(duì)于 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)目啟動(dòng)后,動(dò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 路徑下!
關(guān)于 "java讀取resources中資源文件路徑以及jar中文件無法讀取怎么解決" 就介紹到此。希望多多支持碩編程。