ini 文件操作指南
- 2019 年 10 月 17 日
- 筆記
今天總結一篇工具箱文章。
ini 類型文件通常作為程式的初始化文件。不同於我們常見的配置文件通篇 key-value 的鍵值對形式,ini 文件在鍵值對的基礎之上還有分類節點,比如我們常見的 Mysql 資料庫的初始化配置文件 my.cnf或my.ini,其內容格式通常是如下這樣的:
[client] port = 3306 socket = /data/3306/mysql.sock [mysqld] user = mysql port = 3306 socket = /data/3306/mysql.sock basedir = /usr/local/mysql datadir = /data/3306/data
對於這種格式的文件的讀取操作,Java中常用 Properties 類是不太好使的。當然,你也可以自己憑著高超的擼碼水平去手寫工具方法進行讀寫操作,但肯定還是比較費神的。實際上我們有第三方工具類庫可供選擇。此處部落客分享的類庫叫 org.dtools.javaini。整個工具包很輕便,能夠支援基本的讀寫,格式校驗等,官方教程很詳細,花很少的時間就能上手。當然,結合項目的使用情況,自己還是需要自己進一步封裝些方法以便更好的使用。前人種樹,後人乘涼,部落客也拋轉引玉的寫了幾個:
package module.ini; import com.alibaba.fastjson.JSONObject; import org.dtools.ini.*; import java.io.File; import java.io.IOException; import java.util.Iterator; import java.util.Map; import java.util.Set; /** * @date: 2019/10/16 19:11 * @author: chen * @desc: org.dtools.javaini-v1.1.00.jar 工具包讀寫ini 文件工具類 */ public class IniUtil { // ini 文件抽象表示 private static IniFile iniFile = null; // 要操作的文件實例 private static File file = null; // 操作 ini 文件的閱讀器和書寫器,通過它們來進行具體的讀和寫操作 private IniFileReader iniFileReader = null; private IniFileWriter iniFileWriter = null; /** * @param filePath 文件路徑 * @param caseSensitive 是否區分大小寫 默認false * @param validator 格式校驗器 */ public IniUtil(String filePath, IniValidator validator, boolean caseSensitive) { file = new File(filePath); iniFile = new BasicIniFile(validator, caseSensitive); try { init(); } catch (IOException e) { e.printStackTrace(); } } public IniUtil(String filePath) { this(filePath, new IniValidator(), false); } public IniUtil(String filePath, IniValidator validator) { this(filePath, validator, false); } public IniUtil(String filePath, boolean caseSensitive) { this(filePath, new IniValidator(), caseSensitive); } /** * 初始化 ini 文件的閱讀器和書寫器 */ private void init() throws IOException { iniFileReader = new IniFileReader(iniFile, file); iniFileWriter = new IniFileWriter(iniFile, file); iniFileReader.read(); } /** * 讀取 ini 文件轉換數據為 Json對象 */ public JSONObject getIniFileInfo() { Iterator<IniSection> sectionIterator = iniFile.iterator(); JSONObject jsonObject = new JSONObject(); while (sectionIterator.hasNext()) { IniSection section = sectionIterator.next(); Iterator<IniItem> itemIterator = section.iterator(); JSONObject child = new JSONObject(); while (itemIterator.hasNext()) { IniItem item = itemIterator.next(); child.put(item.getName(), item.getValue()); } jsonObject.put(section.getName(), child); } return jsonObject; } /** * 獲取某個節點下的所有鍵值對 */ public JSONObject getIniBySection(String sectionName) throws Exception { IniSection section = getSection(sectionName); Iterator<IniItem> iterator = section.iterator(); JSONObject jsonObject = new JSONObject(); while (iterator.hasNext()) { IniItem item = iterator.next(); jsonObject.put(item.getName(), item.getValue()); } return jsonObject; } /** * 獲取某個節點下某個條目的值 */ public Object getItemByName(String sectionName, String itemName) throws Exception { JSONObject iniBySection = this.getIniBySection(sectionName); return iniBySection.get(itemName); } /** * 新增或修改某節點條目 */ public void addOrUpdateItem(String sectionName, String itemName, String itemValue) throws Exception { IniSection section = getSection(sectionName); IniItem iniItem = section.addItem(itemName); if (iniItem == null) iniItem = section.getItem(itemName); iniItem.setValue(itemValue); iniFileWriter.write(); } /** * 新增或修改某節點條目 可添加註釋 */ public void addOrUpdateItem(String sectionName, String itemName, String itemValue,String comment) throws Exception { IniSection section = getSection(sectionName); IniItem iniItem = section.addItem(itemName); if (iniItem == null) iniItem = section.getItem(itemName); iniItem.setValue(itemValue); iniItem.setPreComment(comment); // 添加前置注釋 iniFileWriter.write(); } /** * 新增或修改某節點條目 */ public void addOrUpdateItems(String sectionName, Map<String, Object> itemMap) throws Exception { IniSection section = iniFile.getSection(sectionName); Set<String> items = itemMap.keySet(); section.addItems(items.toArray(new String[0])); iniFileWriter.write(); } /** * 新增節點 */ public void addSection(String sectionName) throws IOException { if (iniFile.addSection(sectionName) == null) return; iniFileWriter.write(); } /** * 刪除 某節點 */ public void removeSection(String sectionName) throws IOException { if (iniFile.removeSection(sectionName) == null) return; iniFileWriter.write(); } /** * 刪除 某條目 */ public void removeItem(String sectionName, String itemName) throws Exception { IniSection section = getSection(sectionName); section.removeItem(itemName); iniFileWriter.write(); } private IniSection getSection(String sectionName) throws Exception { if (!iniFile.hasSection(sectionName)) { throw new Exception("The ini file【" + file.getName() + "】 has no section named " + sectionName); } return iniFile.getSection(sectionName); } }
作為一個比較簡單的工具包,應對 ini 類型文件基本的增刪改查足夠了。如果你要深度使用,還有些問題需要你自己來解決——
① 工具包中對文件默認採用 ASCII 編碼,所以對ASCII 碼之外的字元比如中文字元就無法支援,如果讀寫過程中出現中文將會亂碼;
② 對注釋的支援也不足夠。常見的注釋為 #,但是作者卻只給了以 ; 和 // 號開頭的注釋,,如果原文件有 # 類型的注釋,讀寫操作後會被清理掉;
由於類庫中並沒有提供設置編碼或注釋標註的方法,所以,比較好的辦法就是自己下載源碼,在源碼上進行改動,然後自己打包到自己的項目中使用。以下是部落客對程式碼的改動經驗——
首先,對於字元的問題,作者是在 IniFIleWriter 類中定義了一個表示字元的常量,去掉 final 修飾符,便於使用過程中動態修改編碼:
其次,對於注釋,作者在 Commentable 介面中定義了表示注釋開頭的 ‘;’ 標識,由於是聲明在介面中,默認就是static final 的,所以要改成動態設置的比較難辦,改動會比較多,比較好的實踐也是最簡單粗暴的方式——直接改成通常的 # 注釋符就可以了:
最後,重新打成 jar 放入你的項目中或放入你的 maven 倉庫。好了,工具方法,就長話短說了,祝使用愉快。
如有什麼問題或錯漏,歡迎留言交流,不勝感激!