Java - Properties和ResourceBundle類學習

一、前言

??在項目的開發(fā)過程中,為了統(tǒng)一配置的管理,我們經(jīng)常需要將一些配置信息根據(jù)環(huán)境的不同,配置在不同的properties中,然后從里面進行讀取。而Properties類作為最基礎(chǔ)也是最經(jīng)常使用的類,通過本文我們來學習一下它的使用,然后再順便學習下其他幾種讀取properties文件的方式。

二、Properties和ResourceBundle類

??Properties表示一個持久的屬性集,屬性列表通過key-value的形式存在,并且key和value都是字符串。我們先來看一下它的繼承結(jié)構(gòu):

1. Properties 繼承結(jié)構(gòu)
public
class Properties extends Hashtable<Object,Object> {  
    /**
     * A property list that contains default values for any keys not
     * found in this property list.
     *
     * @serial
     */
    protected Properties defaults;
     
    public Properties() {
        this(null);
    }

    public Properties(Properties defaults) {
        this.defaults = defaults;
    }
}

看到它的繼承結(jié)構(gòu),就知道這個類已經(jīng)存在好久了。該類繼承自Hashtable,所以該類擁有Map的一切功能,所以Map的put或者putAll方法都可以使用。

不過由于Properties中的每個key及value都是字符串,所以官方強烈反對使用它們,因為這些方法允許key或者value不是字符串,如果在set或get操作的時候,不是字符串的話,則會提示異常,所以建議使用的則是諸如setProperty這些方法。

2. Properties常用方法

這里Map相關(guān)的方法就不介紹了,主要介紹下自定義的方法:

2.1 setProperty方法
public synchronized Object setProperty(String key, String value) {
    return put(key, value);
}

底層通過Hashtable的put方法來實現(xiàn),該方法的目的就是強制對屬性的key和value都使用字符串的形式;

2.2 getProperties方法
public String getProperty(String key)
public String getProperty(String key, String defaultValue) {
    String val = getProperty(key);
    return (val == null) ? defaultValue : val;
}

獲取屬性列表中屬性的key對應的值,第二個重載方法表示如果獲取不到值返回參數(shù)中提供的默認值。

2.3 load方法
public synchronized void load(Reader reader) throws IOException
public synchronized void load(InputStream inStream) throws IOException

load方法表示從輸入流(字節(jié)流和字符流)中讀取屬性列表到Properties中,讀取的時候按照行進行讀取。而有關(guān)讀取行及相關(guān)轉(zhuǎn)義的說明,可以參考對應的API文檔,上面有詳細的說明。

2.4 loadFromXML方法
public synchronized void loadFromXML(InputStream in)
        throws IOException, InvalidPropertiesFormatException

從輸入流中讀取XML文件中的所有屬性,注意XML文檔必須有相應的DTD聲明:

<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
2.5 store方法
public void store(Writer writer, String comments)
    throws IOException

public void store(OutputStream out, String comments)
    throws IOException

和load的功能相反,將Properties的屬性列表寫入到輸出流,其中參數(shù)表示對屬性列表的說明。

2.6 storeToXML方法
public void storeToXML(OutputStream os, String comment)
    throws IOException

public void storeToXML(OutputStream os, String comment, String encoding)
    throws IOException

將屬性寫入到xml,并可以指定的編碼格式。

2.7 propertyNames和stringPropertyNames方法
public Enumeration<?> propertyNames()
public Set<String> stringPropertyNames()

兩個方法都是返回Properties屬性列表中所有key,前者返回所有枚舉,后者返回類型是字符串,注意如果沒有在主屬性列表中找到同名的鍵,則在默認屬性列表中進行查找。

2.8 list方法
public void list(PrintStream out)
public void list(PrintWriter out)

將屬性列表輸出到指定的輸出流,這個方法對調(diào)試很有用。

3. ResourceBundle簡介

??ResourceBundle沒有繼承什么類,是一個單個的抽象類,該類可以說是國際化版的Properties,簡單說就是可以根據(jù)本地化或語言的不同讀取不同的配置文件,但要注意的一點是使用ResourceBundle讀取的時候,properties的命名是有一定規(guī)范的:

名稱_語言代碼_國家代碼.properties
// 如果是默認的
自定義名.properties
// 例如
myres_en_US.properties
myres_zh_CN.properties
myres.properties

??當指定的Locale是CN的時候,如果myres_zh_CN.properties、myres.properties兩個文件都存在,則優(yōu)先會使用myres_zh_CN.properties,當myres_zh_CN.properties不存在時候,會使用默認的myres.properties。

4. ResourceBundle常用方法
4.1 getBundle方法

ResourceBundle提供了多個重載的靜態(tài)getBundle方法,用于獲取資源文件,這里我們不多介紹,后續(xù)看實例即可:

public static final ResourceBundle getBundle(String baseName)
public static final ResourceBundle getBundle(String baseName,
                                                 Locale locale)
public static ResourceBundle getBundle(String baseName, Locale locale,
                                           ClassLoader loader)
public static final ResourceBundle getBundle(String baseName,
                                                 Control control)
public static ResourceBundle getBundle(String baseName, Locale targetLocale,
                                           ClassLoader loader, Control control)
4.2 getObject,getString,getStringArray方法
  1. getString方法比較簡單,就是根據(jù)key獲取屬性列表中key對應的value,key和value都是String;
  2. getStringArray方法,用于獲取字符串數(shù)組,返回值是字符串數(shù)組;
  3. getObject方法,通用的獲取方法,獲取其他任何類型;
public final String getString(String key)
public final String[] getStringArray(String key)
public final Object getObject(String key)
4.3 keySet,getKeys,containsKey方法

這幾個方法都比較簡單,見名知義,其中g(shù)etKeys表示返回key的枚舉形式。

public Set<String> keySet()
public abstract Enumeration<String> getKeys();
public boolean containsKey(String key)
4.4 getBaseBundleName,getLocale方法

getBaseBundleName方法就是獲取加載的資源文件的文件名的,getLocale獲取本地化環(huán)境信息的。

public String getBaseBundleName()
public Locale getLocale()
4.5 clearCache方法

通過getBundle方法讀取資源文件,獲取ResourceBundle時是從緩存中獲取的,如果已經(jīng)緩存,工廠方法將多次返回相同的資源實例,而clearCache方法就是用于清除緩存的:

public static final void clearCache()
public static final void clearCache(ClassLoader loader)

這里參考自:51cto - java.util.ResourceBundle使用詳解

4. 簡單示例

接下來我們來簡單看下這些方法的相關(guān)使用說明。

4.1 Properties 通過store方法寫入對應的文件中

??首先我們調(diào)用setProperty方法會將key-value存于內(nèi)存中,此時可以通過getProperty方法讀取,propertyNames方法進行遍歷,但是并沒有將鍵值對持久化到屬性文件中,故需要調(diào)用store方法持久化鍵值對到屬性文件中。

Properties properties = new Properties();
try {
    OutputStream output = new FileOutputStream("cache.properties");
    properties.setProperty("redis.server.address", "127.0.0.1");
    properties.setProperty("redis.server.port", "6379");
    properties.setProperty("redis.server.password", "");
    properties.setProperty("redis.server.timeout", "2000");
    properties.store(output, "緩存文件配置測試");
} catch (IOException io) {
    io.printStackTrace();
} finally {
    ...
}

最終生成的cache.properties文件:

#緩存文件配置測試
#Sun Aug 19 12:27:05 CST 2018
redis.server.timeout=2000
redis.server.address=127.0.0.1
redis.server.password=
redis.server.port=6379
4.2 Properties使用load方法加載

同樣,我們可以通過load方法將屬性文件中的屬性加載到Properties對象中,然后進行訪問:

Properties properties = new Properties();
InputStream inputStream = null;
try {
    inputStream = new FileInputStream("cache.properties");
    properties.load(inputStream);
    for (String key : properties.stringPropertyNames()) {
        System.out.println(key + "=" + properties.getProperty(key));
    }
} catch (IOException io) {
    io.printStackTrace();
} finally {
    ...
}

最終結(jié)果:

redis.server.timeout=2000
redis.server.address=127.0.0.1
redis.server.password=
redis.server.port=6379

因為Properties其實是一個Map,所以Map的遍歷方式也適用于Properties,也可也借助Properties的propertyNames方法來進行遍歷:

Enumeration<?> e = properties.propertyNames();
while (e.hasMoreElements()) {
    String key = (String) e.nextElement();
    String value = properties.getProperty(key);
    System.out.println(key + "=" + value);
}
4.3 ResourceBundle簡單實例

我們先定義三個資源文件,放到src的根目錄下面:
myres.properties

aaa=good 
bbb=thanks

myres_en_US.properties

aaa=good 
bbb=thanks

myres_zh_CN.properties

aaa=好
bbb=謝謝

添加測試代碼:

public static void main(String[] args) {
    Locale locale1 = new Locale("zh", "CN");
    ResourceBundle resb1 = ResourceBundle.getBundle("cache", locale1);
    System.out.println(resb1.getString("aaa"));

    ResourceBundle resb2 = ResourceBundle.getBundle("cache", Locale.getDefault());
    System.out.println(resb1.getString("aaa"));

    Locale locale3 = new Locale("en", "US");
    ResourceBundle resb3 = ResourceBundle.getBundle("cache", locale3);
    System.out.println(resb3.getString("aaa"));
}

output:

好
好
good 

這里需要注意下,通過getBundle方法來獲取的時候,參數(shù)不用加properties后綴,只需要文件名就可以了,并且默認訪問的路徑是src,如果文件保存在其他目錄,記得修改到對應的目錄。

5. 其他讀取properties文件的方法
5.1 Properties其他獲取InputStream的方法

在這里,其實讀取properties都是通過Properties來實現(xiàn)的,不過不同的是獲取InputStream流的方式,我們來看一下各種獲取InputStream流的方式:

    1. 從File文件獲?。?/li>
InputStream inputStream = new FileInputStream(new File ("cache.properties"));
    1. 根據(jù)ClassLoader的getResourceAsStream方法來獲取。其中該方法又分為兩種方式:
  1. Class.getResourceAsStream(String path) : path 不以’/'開頭時默認是從此類所在的包下取資源,以’/'開頭則是從ClassPath根下獲取。其實只是通過path構(gòu)造一個絕對路徑,最終還是由ClassLoader獲取資源;
  2. Class.getClassLoader.getResourceAsStream(String path) :默認則是從ClassPath根下獲取,path不能以’/'開頭,最終是由ClassLoader獲取資源;
  3. ServletContext.getResourceAsStream(String path):默認從WebAPP根目錄下取資源,Tomcat下path是否以’/'開頭無所謂,當然這和具體的容器實現(xiàn)有關(guān);

這里參考自:iteye - Java中g(shù)etResourceAsStream的用法

InputStream inputStream = PropertiesTest.class.getResourceAsStream("cache.properties");
    1. 通過URL來獲取:
URL url = new URL("path");
InputStream inputStream= url.openStream();
    1. 如果是Spring環(huán)境,還可以通過ResourceLoader的getResource得到Resource,然后通過Resource的getInputStream來得到流:
ResourceLoader resourceLoader = new DefaultResourceLoader();
Resource resource = resourceLoader.getResource("/config/cache.properties");
inputStream = resource.getInputStream();
5.2 ResourceBundle類相關(guān)方法

前面也已經(jīng)簡單介紹過,我們可以借助java.util.ResourceBundle的getBundle靜態(tài)方法來獲取資源實例:

Locale locale1 = new Locale("zh", "CN");
ResourceBundle resb1 = ResourceBundle.getBundle("cache", locale1);

另外,也可以借助實現(xiàn)類 PropertyResourceBundle 通過從輸入流中進行讀?。?/p>

inputStream = new FileInputStream("cache.properties");
ResourceBundle resource = new PropertyResourceBundle(inputStream);

不過如果有興趣的話可以看下PropertyResourceBundle的構(gòu)造方法,它其實是借助Properties和HashMap來實現(xiàn)的:

public PropertyResourceBundle (InputStream stream) throws IOException {
    Properties properties = new Properties();
    properties.load(stream);
    lookup = new HashMap(properties);
}

private Map<String,Object> lookup;

三、總結(jié)

??到這里,就基本介紹完了Properties和ResourceBundle類及如何讀取properties文件,其實,介紹的都比較基礎(chǔ),需要注意的可能就兩點吧:一是路徑的問題,二是流的關(guān)閉和異常處理問題。

本文參考自:
Java Properties類使用詳解
Java讀取properties文件的思考 - this & getClass

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,606評論 19 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,138評論 25 708
  • 最近,我遇見了一位蜜汁歡樂的的哥,他有種本事,能把平淡的生活過成節(jié)日。跟他聊天很引人入勝,似乎是一個能量場,能把人...
    千語樹閱讀 336評論 0 1
  • 暮色四合,風寒星冷。塵世如潮,可否醉一場不再醒來……門前鄰人種植的蔬菜,經(jīng)了一場雨,長勢很好,已經(jīng)可以食用了。看天...
    程杜閱讀 164評論 0 0
  • 《眼淚》 也許只有眼淚 曾經(jīng)相信過愛情 但我現(xiàn)在已經(jīng)欲哭無淚 《悲劇》 兩個人的相處本來就是一場博弈 或許最后也會...
    幻夢邪魂閱讀 374評論 0 2

友情鏈接更多精彩內(nèi)容