前幾天,公司項目中有一個需求是讀取配置文件的,而且最好能夠保證加載到內存中的順序能夠和配置文件中的順序一致,但是,如果使用 jdk 中提供的 Properties 類的話,讀取配置文件后,加載到內存中的順序是隨機的,不能保證和原文件的順序一致,因此,jdk 提供的 Properties 是不行的。
由於有這樣的需求,而 Java 的 Properties 類又不能實現,因此只能想別的辦法。我曾經想過,在把配置文件加載到內存后,對其進行排序,但這個方案會有很多限制,而且也有問題。配置文件中的信息會有很多,如果對其進行再排序的話,首先會影響系統的性能,其次,對程序的執行效率來講,也會有一定的影響。最后,經過一番查證之后,同事找到了一篇類似的文章。
解決方案
從文章中了解到,Java 的 Properties 加載屬性文件后是無法保證輸出的順序與文件中一致的,因為 Properties 是繼承自 Hashtable 的, key/value 都是直接存在 Hashtable 中的,而 Hashtable 是不保證進出順序的。
文章中已經給提供了代碼,思路是繼承自 Properties,覆蓋原來的 put/keys,keySet,stringPropertyNames 即可,其中用一個 LinkedHashSet 來保存它的所有 key。完整代碼如下:
import java.util.Collections; import java.util.Enumeration; import java.util.LinkedHashSet; import java.util.Properties; import java.util.Set; /** * OrderedProperties * @author hanwl * @date 2018-11-13 * @userd 使得Properties有序 */ public class OrderedProperties extends Properties { private static final long serialVersionUID = 4710927773256743817L; private final LinkedHashSet<Object> keys = new LinkedHashSet<Object>(); @Override public Enumeration<Object> keys() { return Collections.<Object> enumeration(keys); } @Override public Object put(Object key, Object value) { keys.add(key); return super.put(key, value); } @Override public Set<Object> keySet() { return keys; } @Override public Set<String> stringPropertyNames() { Set<String> set = new LinkedHashSet<String>(); for (Object key : this.keys) { set.add((String) key); } return set; } }
調用方法:
public class demo { Properties prop = new OrderedProperties(); File appDir = GlobalVars.getLocalAppDataDir(); File dir = new File(appDir, "userHistory/"); if (!dir.exists()) { dir.mkdirs(); } try { OutputStreamWriter oStreamWriter = new OutputStreamWriter(new FileOutputStream(dir+"\\user.properties",true), "utf-8"); //FileOutputStream fileOutputstream = new FileOutputStream(dir+"\\user.properties", false); prop.setProperty("serverUrl", serverUrlTextField.getText()); prop.setProperty("userName", userNameTextField.getText()); prop.setProperty("password", passwordField.getText()); prop.store(oStreamWriter, null); oStreamWriter.close(); } catch (Exception e) { e.printStackTrace(); } Properties prop = new OrderedProperties(); File appDir = GlobalVars.getLocalAppDataDir(); File dir = new File(appDir, "userHistory/"); if(new File(dir+"\\user.properties").exists()){ try { InputStreamReader iStreamReader = new InputStreamReader(new FileInputStream(dir+"\\user.properties"),"utf-8"); prop.load(iStreamReader); Iterator<String> it = prop.stringPropertyNames().iterator(); while (it.hasNext()) { String key = it.next(); String value = prop.getProperty(key); System.out.println(key+":"+value); } iStreamReader.close(); } catch (Exception e) { e.printStackTrace(); } } }
/** * 返回程序本地數據存儲目錄 * C:\Users\Administrator\AppData\Local\Founder\PublisherClient * C:\Users\Administrator\AppData\Local\Founder\PrinterClient * C:\Users\Administrator\AppData\Local\Founder\TypeSettingClient * @return */ public static File getLocalAppDataDir() { String appDataPath; if (Util.isMac()) { appDataPath = System.getProperty("user.home") + "/Library/"; } else if (NativeUtil.libraryLoaded()) { appDataPath = NativeUtil.getLocalAppDataFolder(); } else { appDataPath = System.getProperty("user.home"); } File founderDir = new File(appDataPath, Util.isWindows() || Util.isMac() ? "Founder" : ".Founder"); File appDir = new File(founderDir, CLIENT_TYPE.getClientName()); appDir.mkdirs(); return appDir; }
結束
這種特定的需求,以前倒是沒怎么接觸過,不給通過這次的經歷,發現了一點,自己的積累還是很少,不多說了,繼續努力吧。
參考: