您好,登錄后才能下訂單哦!
今天小編給大家分享的是Java讀取resources中資源文件路徑以及jar中文件無法讀取如何解決,相信很多人都不太了解,為了讓大家更加了解,所以給大家總結了以下內容,一起往下看吧。一定會有所收獲的哦。
現象
作為一個剛開始學習java的新人,很多東西都是摸著石頭過河,踩坑是常有的事。這不,今天我將maven管理的一個spring boot的WebAPP部署到服務器上,運行直接報錯!納尼!!!本地跑得好好的,一到服務器就出問題,關鍵是日志文件中的日志不全,無法馬上定位到問題。好吧,一步一步排除問題吧!
定位
是不是windows與linux的區別?不是,我在windows上跑了一下打包后的代碼,也出問題了,打包前沒問題,打包后出問題了,包有毒!然后我開放了日志,一步一步調試(蛋疼啊),最終發現配置文件沒有加載,路徑出了問題。。。
工程文件結構如下所示,目標是讀取resources/python/kafka_producer.py文件
采用getResource進行讀取:
URL urlPath = this.getClass().getResource("/python/kafka_producer.py"); String execStr = String.format("python %s", urlPath.getPath().substring(1));
它是在target文件中讀取,這時文件是我們熟悉的文件。正常讀取,運行。
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);
如果你需要運行腳本文件,這時是不能直接通過路徑獲取的,具體可以看博客點擊。你需要重新將流寫入文件中,在運行,當然,也可以打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程序中讀取resources資源下的文件,由于對Java結構了解不透徹,遇到很多坑。
正常在Java工程中讀取某路徑下的文件時,可以采用絕對路徑和相對路徑,絕對路徑沒什么好說的,相對路徑,即相對于當前類的路徑。在本地工程和服務器中讀取文件的方式有所不同,以下圖配置文件為例:
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 資源文件!
當工程部署到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() 的區別
a)class.getClassLoader().getResourceAsStream(Stringname)默認從classpath中找文件(文件放在resources目錄下),name不能帶"/",否則會拋空指針。采用相對路徑, "/"就相當于當前進程的根目錄,即項目根目錄;
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進行獲取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>
重點:SpringBoot項目啟動后,動態的讀取類路徑下文件數據
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();
注意:此時我想讀取 jar 包中根路徑下的 HelloServiceEncryptFile.txt 文件,然后重新寫入到根路徑下的 com.study/service 路徑下!
關于Java讀取resources中資源文件路徑以及jar中文件無法讀取如何解決就分享到這里了,希望以上內容可以對大家有一定的參考價值,可以學以致用。如果喜歡本篇文章,不妨把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。