如何配置和讀取屬性文件
- 1.屬性文件介紹
- 1.1 什么是屬性文件
- 1.2屬性文件規范
- 1.3 屬性文件優缺點
- 2.屬性文件讀取
- 4.spring和屬性文件
- 4.1利用注解讀取
- 4.2配置文件里直接引用
- 4.屬性文件寫入
- 5.注意事項
- 5.總結
1.屬性文件介紹
1.1 什么是屬性文件
Java開發中,我們經常需要讀取和寫入配置文件,用來存儲程序中的一些配置信息,例如數據庫的連接信息、郵件和Web服務器的信息、消息隊列的信息等等。配置文件一般都是key-value形式,且它的key-value一般都是String-String類型的,因此我們完全可以用Map<String, String>來表示它。
但因為配置文件特別常用,所以Java集合庫給我們提供了一個Properties類來表示一組“配置”,專門用來處理key-value形式的配置信息。Properties類可以表示一個持久的屬性集,每個鍵及其對應的值都是字符串類型,它可以把配置信息保存在一個IO流中,或是從一個IO流中加載配置信息,因此很適合用來處理配置文件。
Properties的內部本質上是一個Hashtable,該類從Hashtable中繼承了get()和put()方法,這些方法的參數簽名是Object。但由于歷史遺留原因,Properties的設計實際上是有問題的,不過為了保持兼容性,現在已經沒法修改了。所以我們在使用Properties時,不要去調用這些從Hashtable繼承來的方法,而應該使用Properties自身關于讀寫配置的方法,比如getProperty()和setProperty()等方法。
1.2屬性文件規范
1.屬性文件都是以鍵值對出現
key=value
2.注釋用#開頭
3.增加可讀性,key很多時候都用xx.xxx表示
eg:
#log4j屬性配置
log4j.rootLogger=DEBUG,A
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=[%t] [%c]-[%p] %m%n# properties文件示例
# 注釋內容以#號開頭
name=Tom
age=22
gender=Male
1.3 屬性文件優缺點
1、Properties文件的優點:
(1)Properties文件結構簡單,易于讀寫、解析。
(2)Properties文件的擴展性強,可以隨時添加、修改、刪除屬性。
(3)Properties文件可以存儲鍵值對類型的數據,非常通用。
(4)Properties文件具有跨平臺性,可以在不同操作系統上使用。
2、Properties文件的缺點:
(1)Properties文件對復雜結構和大量數據的支持不夠好。
(2)Properties文件格式和內容沒有規范,容易產生格式錯誤、解析異常等問題。
3、注意事項:
(1)Properties文件不是加密文件,存儲敏感信息時建議進行加密處理。
(2)Properties文件的編碼一般使用ISO-8859-1,建議不要使用Unicode編碼。
2.屬性文件讀取
屬性文件本身是一個文件,要讀取一個文件,需要獲得這個文件的InputStream。
在利用Properties類起封裝文件流,就可以用getProperty(key)讀取屬性值
java提供了多種方式,如果屬性文件放置在類目錄下,用 ClassLoader.getSystemResourceAsStream是最推薦的。其中最容易出錯的是文件路徑的定位
方法 | 說明 |
---|---|
this.getClass().getClassLoader().getResourceAsStream(fileName) | 默認從class根目錄,不加/ |
this.getClass().getResourceAsStream(fileName) | 默認當前class目錄,從根目錄算,要加/ |
ClassLoader.getSystemResourceAsStream(fileName) | 默認從class根目錄,不加/ |
new FileInputStream(fileName) | 絕對路徑,不推薦 |
reader = new FileReader(fileName) | 絕對路徑,不推薦 |
Resource resource = new ClassPathResource(fileName); | 等價ClassLoader |
ResourceBundle rb2 = ResourceBundle.getBundle(fileName); | 等價ClassLoader |
package com.jsoft.test;import org.junit.Test;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PropertiesLoaderUtils;import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Properties;
import java.util.ResourceBundle;/*** @class: com.jsoft.test.PropertiesTest* @description:* @author: jiangzengkui* @company: 教育家* @create: 2023-12-07 23:07*/
public class PropertiesTest {/*** 1. 方式一* 從當前的類加載器的this.getClass().getResourcesAsStream來獲取* InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(name)* 前提:屬性文件必須放置在類的目錄結構里* 文件路徑判斷:* this.getClass().getResourceAsStream是從當前類去尋找資源* 1.如果不加路徑,則從當前class類的目錄里找* 2.如果有路徑,但沒有根路徑,則從當前類的子目錄找* eg:* 當前類:com.jsoft.MyProper* this.getClass().getClassLoader().getResourceAsStream("user/user.properties")* 是尋找com.jsoft.user類目錄里是否有屬性文件* @throws IOException* 3.如果有路徑,而且有根路徑,則從classes根目錄找* this.getClass().getResourceAsStream("/com/jsoft/test/user/user1.properties");*/@Testpublic void t1() throws IOException {InputStream inputStream=null;inputStream = this.getClass().getResourceAsStream("user.properties");inputStream = this.getClass().getResourceAsStream("user/user.properties");inputStream = this.getClass().getResourceAsStream("/com/jsoft/test/user/user1.properties");inputStream = this.getClass().getResourceAsStream("/log4j.properties");printProper(inputStream);}/*** 2. 方式二* this.getClass().getClassLoader()是獲得java類加載器ClassLoader* ClassLoader.getResourceAsStream默認就是從根目錄加載,路徑不能從/開始* 如:log4j.properties就表示從class根目錄了,加/log4j.properties反而出錯* @throws IOException*/@Testpublic void t2() throws IOException {InputStream inputStream=null;//放在在class根目錄inputStream = this.getClass().getClassLoader().getResourceAsStream("log4j.properties");//放置在classpath/com/jsoft/testinputStream = this.getClass().getClassLoader().getResourceAsStream("com/jsoft/test/user.properties");//放置在classpath/com/jsoft/test/userinputStream = this.getClass().getClassLoader().getResourceAsStream("com/jsoft/test/user/user1.properties");printProper(inputStream);}/*** 3.方式三:* 直接用類加載器的靜態方法* ClassLoader.getSystemResourceAsStream()* 等價于* this.getClass().getClassLoader().getResourceAsStream()* 對路徑的要求也是一樣,都是不需要加根路徑/* @throws IOException*/@Testpublic void t3() throws IOException {InputStream inputStream=null;//放在在class根目錄inputStream = ClassLoader.getSystemResourceAsStream("log4j.properties");//放置在classpath/com/jsoft/testinputStream = ClassLoader.getSystemResourceAsStream("com/jsoft/test/user.properties");//放置在classpath/com/jsoft/test/userinputStream = ClassLoader.getSystemResourceAsStream("com/jsoft/test/user/user1.properties");printProper(inputStream);}/*** 4.方法四* 用FileInputStream(文件)獲取文件流,這種方法:* 1.取工程的路徑* 2.取絕對路徑* 這個方法適用于屬性文件沒有放置classses目錄下,用絕對路徑可訪問,原則不推薦* @throws IOException*/@Testpublic void t4() throws IOException {InputStream inputStream=null;inputStream=new FileInputStream("src/main/resources/log4j.properties");inputStream=new FileInputStream("target/classes/log4j.properties");inputStream=new FileInputStream("D:/java/idea_project/mybatis/basic/target/classes/log4j.properties");printProper(inputStream);}/*** 5. 方法五* 使用 FileReader reader = new FileReader(fileName)* 和FileInputStream一樣,也需要絕對路徑,不推薦* @throws IOException*/@Testpublic void t5()throws IOException {FileReader reader = new FileReader("D:/java/idea_project/mybatis/basic/target/classes/log4j.properties");Properties properties=new Properties();properties.load(reader);printProper(properties);}/*** 6.方法六* spring提供的幫助類* 和ClassLoader一樣,不需要根路徑*/@Testpublic void t6() throws IOException {Resource resource = new ClassPathResource("log4j.properties");Properties properties = PropertiesLoaderUtils.loadProperties(resource);printProper(properties);}/*** 7.方法七* ResourceBundle.getBundle的路徑訪問和 Class.getClassLoader.getResourceAsStream類似,* 默認從根目錄下讀取,也可以讀取resources目錄下的文件* ResourceBundle rb = ResourceBundle.getBundle("b")* 不需要指定文件名的后綴,只需要寫文件名前綴即可* 可用ResourceBundle.getString(key)取值*/@Testpublic void t7() throws IOException {//讀取class根路徑的log4j.properties文件,不需要文件后綴ResourceBundle rb2 = ResourceBundle.getBundle("log4j");//可用ResourceBundle.getString(key)取值System.out.println("log4j.appender.A1==="+rb2.getString("log4j.appender.A1"));for(String key : rb2.keySet()){String value = rb2.getString(key);System.out.println(key + ":" + value);}}/*** 獲得屬性值* @param inputStream* @param key* @return* @throws IOException*/public static String getVal( InputStream inputStream,String key) throws IOException {Properties properties=new Properties();properties.load(inputStream);return properties.getProperty(key);}public static void printProper(InputStream inputStream)throws IOException {Properties properties=new Properties();properties.load(inputStream);for(Map.Entry<Object, Object> entry: properties.entrySet()){System.out.println(entry.getKey()+"="+entry.getValue());}}public static void printProper(Properties properties)throws IOException {for(Map.Entry<Object, Object> entry: properties.entrySet()){System.out.println(entry.getKey()+"="+entry.getValue());}}
}
4.spring和屬性文件
4.1利用注解讀取
配置里面注入屬性文件
<context:property-placeholder location="classpath:salesman.properties"/><!-- 或者多個 --><bean id="cfgproperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"><property name="locations"><list><value>WEB-INF/config/jdbc.properties</value><value>WEB-INF/config/product.properties</value><value>WEB-INF/config/mail.properties</value><value>WEB-INF/config/ding.properties</value></list></property><qualifier value="main"/></bean>
<!-- 屬性文件讀取 --><bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><property name="properties" ref="cfgproperties" /><property name="fileEncoding" value="utf-8" /></bean>
在Java中使用這個@Value(“${ }”)注解 讀取 properties中的參數
@Value("${filePath}") private String filePath;public void setFilePath(String filePath) {System.out.println(filePath);this.filePath = filePath;
}
4.2配置文件里直接引用
直接用${key}取值
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="driverClass" value="${jdbc.driverClassName}" /><property name="jdbcUrl" value="${jdbc.url}" /><property name="user" value="${jdbc.username}" /><property name="password" value="${jdbc.password}" /><property name="autoCommitOnClose" value="true"/><property name="checkoutTimeout" value="${cpool.checkoutTimeout}"/><property name="initialPoolSize" value="${cpool.minPoolSize}"/><property name="minPoolSize" value="${cpool.minPoolSize}"/><property name="maxPoolSize" value="${cpool.maxPoolSize}"/><property name="maxIdleTime" value="${cpool.maxIdleTime}"/><property name="acquireIncrement" value="${cpool.acquireIncrement}"/><property name="maxIdleTimeExcessConnections" value="${cpool.maxIdleTimeExcessConnections}"/></bean>
4.屬性文件寫入
寫入屬性文件不常用
// 代碼示例:寫入Properties文件
Properties prop = new Properties(); // 創建Properties對象
OutputStream out = new FileOutputStream("config.properties"); // 創建輸出流
prop.setProperty("name", "Tom"); // 設置屬性名和屬性值
prop.setProperty("age", "22");
prop.store(out, "Properties example"); // 將Properties對象寫入Properties文件
5.注意事項
1、Properties文件的優點:
(1)Properties文件結構簡單,易于讀寫、解析。
(2)Properties文件的擴展性強,可以隨時添加、修改、刪除屬性。
(3)Properties文件可以存儲鍵值對類型的數據,非常通用。
(4)Properties文件具有跨平臺性,可以在不同操作系統上使用。
2、Properties文件的缺點:
(1)Properties文件對復雜結構和大量數據的支持不夠好。
(2)Properties文件格式和內容沒有規范,容易產生格式錯誤、解析異常等問題。
3、注意事項:
(1)Properties文件不是加密文件,存儲敏感信息時建議進行加密處理。
(2)Properties文件的編碼一般使用ISO-8859-1,建議不要使用Unicode編碼。
5.總結
Properties文件是Java中一種存儲配置文件的文件類型,其通過鍵值對的形式存儲數據,通常用于存儲應用程序的配置信息、國際化內容、資源文件等。在Java中, Properties文件可以通過java.util.Properties類進行讀寫操作。Properties文件結構簡單,易于讀寫、解析,擴展性強,并且具有跨平臺性。但它也有局限性,對于復雜結構和大量數據的支持不夠好,容易產生格式錯誤、解析異常等問題。