Java代碼實(shí)現(xiàn)對(duì)properties文件有序的讀寫的示例
最近遇到一項(xiàng)需求,要求把properties文件中的內(nèi)容讀取出來(lái)供用戶修改,修改完后需要再重新保存到properties文件中。很簡(jiǎn)單的需求吧,可問題是Properties是繼承自HashTable的,直接通過(guò)keySet()、keys()或entrySet()方法對(duì)Properties中的元素進(jìn)行遍歷時(shí)取出來(lái)的內(nèi)容順序與properties文件中的順序不一致,這是問題一;問題二是就算取出來(lái)的時(shí)候是有序的,保存到文件中時(shí)又是無(wú)序的了。
當(dāng)然,解決這兩個(gè)問題的方法有很多。我最終采用的方法是自定義一個(gè)PropertiesUtil類,該類繼承自Properties。PropertiesUtil提供一個(gè)返回由key按照存入順序組成的List的方法,getKeyList(),這樣問題一就解決了。那如何保證getKeyList()方法返回的就是有序的key組成的集合呢?我查看了一下Properties方法的源碼,發(fā)現(xiàn)其setProperty()方法實(shí)際上就是調(diào)用了父類HashTable的put()方法,其次Properties在從文件中加載內(nèi)容時(shí)是按照文件順序進(jìn)行讀取,然后調(diào)用父類HashTable的put()方法進(jìn)行儲(chǔ)存。所以問題的解決辦法就是PropertiesUtil持有一個(gè)私有的可以有序存儲(chǔ)key的集合,然后重寫父類的put()方法,在方法體中照常通過(guò)super.put()進(jìn)行屬性的存儲(chǔ),同時(shí)將key添加到存儲(chǔ)key的集合中。
Properties提供有save()方法和store()方法可以將當(dāng)前對(duì)象的內(nèi)容存放到指定的輸出流中,但它們的底層邏輯都是一樣的。通過(guò)調(diào)用keys()方法獲取一個(gè)Enumeration,然后對(duì)該Enumeration進(jìn)行遍歷,依次將對(duì)應(yīng)的key和value寫入到輸出流中,所以要保證寫入是有序的,就要保證遍歷keys()返回的Enumeration時(shí)取出的元素key是有序的。所以解決方法是重寫keys()方法,保證遍歷返回的Enumeration時(shí)得到的key是有序的。
下面就示范怎么按順序讀properties文件,以及還得按原來(lái)的順序?qū)憄roperties文件。
package com.lxk.propertyFileTest;
import java.util.*;
/**
* Created by lxk on 2017/5/2
*/
public class OrderedProperties extends Properties {
private static final long serialVersionUID = -4627607243846121965L;
/**
* 因?yàn)長(zhǎng)inkedHashSet有序,所以,key在調(diào)用put()的時(shí)候,存放到這里也就有序。
*/
private final LinkedHashSet<Object> keys = new LinkedHashSet<>();
@Override
public Enumeration<Object> keys() {
return Collections.enumeration(keys);
}
/**
* 在put的時(shí)候,只是把key有序的存到{@link OrderedProperties#keys}
* 取值的時(shí)候,根據(jù)有序的keys,可以有序的取出所有value
* 依然調(diào)用父類的put方法,也就是key value 鍵值對(duì)還是存在hashTable里.
* 只是現(xiàn)在多了個(gè)存key的屬性{@link OrderedProperties#keys}
*/
@Override
public Object put(Object key, Object value) {
keys.add(key);
return super.put(key, value);
}
/**
* 因?yàn)閺?fù)寫了這個(gè)方法,在(方式一)的時(shí)候,才輸出有序。
* {@link MainOrder#printProp}
*/
@Override
public Set<String> stringPropertyNames() {
Set<String> set = new LinkedHashSet<>();
for (Object key : this.keys) {
set.add((String) key);
}
return set;
}
/**
* 因?yàn)閺?fù)寫了這個(gè)方法,在(方式二)的時(shí)候,才輸出有序。
* {@link MainOrder#printProp}
*/
@Override
public Set<Object> keySet() {
return keys;
}
//這個(gè)就不設(shè)置有序了,因?yàn)樯婕暗紿ashTable內(nèi)部類:EntrySet,不好復(fù)寫。
//public LinkedHashSet<Map.Entry<Object, Object>> entrySet() {
// LinkedHashSet<Map.Entry<Object, Object>> entrySet = new LinkedHashSet<>();
// for (Object key : keys) {
//
// }
// return entrySet;
//}
/**
* 因?yàn)閺?fù)寫了這個(gè)方法,在(方式四)的時(shí)候,才輸出有序。
* {@link MainOrder#printProp}
*/
@Override
public Enumeration<?> propertyNames() {
return Collections.enumeration(keys);
}
}
上面是繼承Java自帶的類,我們做的主要是實(shí)現(xiàn)有序,其他的還是原來(lái)的樣子就行。
看下整個(gè)的類繼承關(guān)系:如下圖:

下面是main方法的類。
package com.lxk.propertyFileTest;
import java.io.*;
import java.util.Enumeration;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
/**
* 讀寫properties文件測(cè)試(帶順序的讀和寫)
* <p>
* Created by lxk on 2017/5/2
*/
public class MainOrder {
public static void main(String[] args) {
Properties prop = readOrderedPropertiesFile();
printProp(prop);
writeOrderedPropertiesFile(prop);
}
/**
* 輸出properties的key和value
*/
public static void printProp(Properties properties) {
System.out.println("---------(方式一)------------");
for (String key : properties.stringPropertyNames()) {
System.out.println(key + "=" + properties.getProperty(key));
}
System.out.println("---------(方式二)------------");
Set<Object> keys = properties.keySet();//返回屬性key的集合
for (Object key : keys) {
System.out.println(key.toString() + "=" + properties.get(key));
}
System.out.println("---------(方式三)------------");
Set<Map.Entry<Object, Object>> entrySet = properties.entrySet();//返回的屬性鍵值對(duì)實(shí)體
for (Map.Entry<Object, Object> entry : entrySet) {
System.out.println(entry.getKey() + "=" + entry.getValue());
}
System.out.println("---------(方式四)------------");
Enumeration<?> e = properties.propertyNames();
while (e.hasMoreElements()) {
String key = (String) e.nextElement();
String value = properties.getProperty(key);
System.out.println(key + "=" + value);
}
}
/**
* 讀Properties文件(有序)
*/
private static Properties readOrderedPropertiesFile() {
Properties properties = new OrderedProperties();
InputStreamReader inputStreamReader = null;
try {
InputStream inputStream = new BufferedInputStream(new FileInputStream("D:testOrder.properties"));
//prop.load(in);//直接這么寫,如果properties文件中有漢子,則漢字會(huì)亂碼。因?yàn)槲丛O(shè)置編碼格式。
inputStreamReader = new InputStreamReader(inputStream, "utf-8");
properties.load(inputStreamReader);
} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
if (inputStreamReader != null) {
try {
inputStreamReader.close();
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
return properties;
}
/**
* 寫Properties文件(有序)
*/
private static void writeOrderedPropertiesFile(Properties properties) {
properties.setProperty("phone", "10086");
OutputStreamWriter outputStreamWriter = null;
try {
//保存屬性到b.properties文件
FileOutputStream fileOutputStream = new FileOutputStream("order.properties", false);//true表示追加打開,false每次都是清空再重寫
//prop.store(oFile, "此參數(shù)是保存生成properties文件中第一行的注釋說(shuō)明文字");//這個(gè)會(huì)兩個(gè)地方亂碼
//prop.store(new OutputStreamWriter(oFile, "utf-8"), "漢字亂碼");//這個(gè)就是生成的properties文件中第一行的注釋文字亂碼
outputStreamWriter = new OutputStreamWriter(fileOutputStream, "utf-8");
properties.store(outputStreamWriter, "lll");
} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
if (outputStreamWriter != null) {
try {
outputStreamWriter.close();
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
}
}
其實(shí)讀和寫,都和使用系統(tǒng)提供的類的差別不大,只是現(xiàn)在讀到了我們自己寫的子類里面去了。
其他的代碼都是一樣樣的。
下面是讀的文件的內(nèi)容截圖:

再然后是,實(shí)際代碼運(yùn)行的結(jié)果截圖:
---------(方式一)------------ 1=11 2=22 3=33 4=44 5=55 6=66 7=77 8=88 9=99 10=18 11漢字=測(cè)試漢字以防亂碼產(chǎn)生 ---------(方式二)------------ 1=11 2=22 3=33 4=44 5=55 6=66 7=77 8=88 9=99 10=18 11漢字=測(cè)試漢字以防亂碼產(chǎn)生 ---------(方式三)------------ 11漢字=測(cè)試漢字以防亂碼產(chǎn)生 9=99 8=88 7=77 6=66 5=55 4=44 3=33 2=22 10=18 1=11 ---------(方式四)------------ 1=11 2=22 3=33 4=44 5=55 6=66 7=77 8=88 9=99 10=18 11漢字=測(cè)試漢字以防亂碼產(chǎn)生
額,太長(zhǎng)了,就不截圖了吧,就給把打印結(jié)果給展示一下得了。
可以看到,只有第三次是無(wú)序的,具體原因,我也在代碼里面解釋過(guò)了。
還有,就是生成的文件的截圖:

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
SpringMVC中的DispatcherServlet結(jié)構(gòu)和初始化詳解
這篇文章主要介紹了SpringMVC中的DispatcherServlet結(jié)構(gòu)和初始化詳解,SpringMVC中Spring容器的關(guān)系是通過(guò)監(jiān)聽方式啟動(dòng)的,那么Spring與Servlet的Web容器(如:Tomcat、jetty)的關(guān)系則是通過(guò)DispatcherServlet進(jìn)行關(guān)聯(lián),需要的朋友可以參考下2024-01-01
Spring框架web項(xiàng)目實(shí)戰(zhàn)全代碼分享
這篇文章主要介紹了Spring框架web項(xiàng)目實(shí)戰(zhàn)全代碼分享,具有一定參考價(jià)值,需要的朋友可以了解下。2017-11-11
如何自動(dòng)生成Mybatis的Mapper文件詳解
這篇文章主要給大家介紹了關(guān)于如何自動(dòng)生成Mybatis的Mapper文件的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Mybatis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07
Spring Cloud 如何保證微服務(wù)內(nèi)安全
這篇文章主要介紹了Spring Cloud 如何保證微服務(wù)內(nèi)安全的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
遠(yuǎn)程調(diào)用@FeignClient注解屬性使用詳解
這篇文章主要為大家介紹了遠(yuǎn)程調(diào)用@FeignClient注解屬性使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10

