看到這個標題,有人會問,現在都用xml做配置檔案了,誰還用INI檔案啊!下面來簡單對比一下xml和ini:
1、XML功能強大表達能力強,同時擴充套件性好。
2、它的主要優勢是異構平臺的整合、通訊。
3、缺點主要是使用複雜,執行庫佔用的資源較多。
4、如果多個程式進行資料交換或是跨平臺通訊則使用功能強大的XML;
5、INI雖表達能力不強,但是簡單實用,介面方便。如果是用於應用程式的配置INI檔案就夠了。
至於哪個更好,應該用哪個,可以根據自己愛好和需求。個人感覺INI檔案操作簡單,就是讀取檔案,處理字串,儲存到檔案,可謂是簡單粗暴。而且內容也比較友好,沒有冗餘的東西。
由於最近專案中用到INI檔案,所以抽空編寫了一個Helper,取名交INIHelper。這裡先不給出它的原始碼,先來看下他的用法。
這裡為了做演示,我建了一個C# 控制檯應用程式,隨便起了個名字,加入了INIHelper這個類。專案結構如圖:
在Debug目錄下面新增了一個config.ini的檔案,內容如下:
下面我們用這個Helper來讀取這個INI檔案的所有內容,程式碼如下:
class Program { static void Main(string[] args) { try { INIHelper helper = new INIHelper("config.ini"); Console.WriteLine(helper.GetValueByName("DBName")); Console.WriteLine(helper.GetValueByName("UserName")); Console.WriteLine(helper.GetValueByName("PassWord")); Console.WriteLine(helper.GetValueByName("Version")); } catch (Exception ex) { Console.WriteLine(ex.Message); } Console.Read(); } }
輸出結果如下:
是不是很方便,這裡還有另外一種寫法,程式碼如下:
class Program { static void Main(string[] args) { try { INIHelper helper = new INIHelper(); helper.LoadINI("config.ini"); Console.WriteLine(helper.GetValueByName("DBName")); Console.WriteLine(helper.GetValueByName("UserName")); Console.WriteLine(helper.GetValueByName("PassWord")); Console.WriteLine(helper.GetValueByName("Version")); } catch (Exception ex) { Console.WriteLine(ex.Message); } Console.Read(); } }
程式碼中加粗的部分就是另外一種寫法,一種方法是在構造時載入ini檔案,另外一種方法時在需要的時候載入。到這裡讀取ini檔案的就說完了,下面來說一下修改ini檔案。這裡我們來修改ini檔案密碼為root,然後儲存到ini檔案中,來看看程式碼怎麼寫:
class Program { static void Main(string[] args) { try { INIHelper helper = new INIHelper(); helper.LoadINI("config.ini"); helper.SetValueByName("PassWord", "root"); helper.SaveINI(); } catch (Exception ex) { Console.WriteLine(ex.Message); } Console.Read(); } }
首先載入ini檔案,然後呼叫SetValueByName方法修改密碼,最後呼叫SaveINI方法儲存。儲存後,可以開啟ini檔案看到內容變了,這裡就不再截圖了。其還支援加密解密,這樣我們的配置檔案內容就不會被被人看到和隨意修改了,加密後的效果如下:
下面來看看INIHelper的具體實現,首先來看構造方法和LoadINI,其實現程式碼如下:
private string newLine = "\r\n"; //換行符 private string filePath = string.Empty; //檔名稱 private string fileContent = string.Empty; //檔案內容 public INIHelper() { } /// <summary> /// 有參構造方法,直接讀取INI檔案 /// </summary> /// <param name="filePath"></param> public INIHelper(string filePath) { this.LoadINI(filePath); } /// <summary> /// 載入並讀取INI檔案 /// </summary> /// <param name="fileName">檔案路徑</param> public void LoadINI(string filePath) { if (filePath.Trim().Length > 0) { this.filePath = filePath; ReadINIFile(); } else { throw new Exception("Invalid file name!"); } }
可以看到在有參構造方法裡面呼叫了LoadINI方法,所以等價於呼叫無參建構函式然後呼叫LoadINI方法。LoadINI方法裡面首先判斷檔案路徑是否合法,合法的話就讀取ini檔案,否則丟擲異常。ReadINIFile方法就是讀取檔案內容,然後賦給fileContent,其實現如下:
/// <summary> /// 讀取INI檔案 /// </summary> private void ReadINIFile() { if (File.Exists(this.filePath)) { try { using (StreamReader sr = new StreamReader(this.filePath)) { this.fileContent = sr.ReadToEnd(); this.fileContent = EncryptionAndDecryption(fileContent); //解密 //如果檔案內容為空或者沒有換行符,則認為是無效的INI檔案。 if (fileContent.Trim().Length <= 0 || !fileContent.Contains("\n")) { throw new Exception("Invalid ini file"); } else { //儲存檔案預設換行符 if (!fileContent.Contains(newLine)) { this.newLine = "\n"; } } } } catch (Exception ex) { throw new Exception("Read file error! Error Message:" + ex.Message); } } else { throw new Exception("File " + filePath + " not found!"); } }
這個已經包含了加密解密的方法,首先讀取檔案內容,解密,然後判斷檔案是否合法,及是否有為空和是否有換行符,然後判斷裡面的換行符是否為預設值,否則修改newLine為檔案預設的換行符。(大家可以修改程式碼,自定分割符。預設是支援\r\n或\n)
/// <summary> /// 讀取INI檔案某個配置項的值 /// </summary> /// <param name="fieldName"></param> /// <returns></returns> public string GetValueByName(string fieldName) { fileContent = fileContent.Replace(newLine, ";"); fileContent = fileContent.Replace(" ", ""); fileContent = fileContent.EndsWith(";") ? fileContent : fileContent + ";"; Regex reg = new Regex("(?<=" + fieldName + "=).*?(?=;)"); Match m = reg.Match(fileContent); return m.Value; } /// <summary> /// 修改INI檔案某個配置項的值 /// </summary> /// <param name="fieldName"></param> /// <param name="value"></param> public void SetValueByName(string fieldName, string value) { string reg = "(?<=" + fieldName + "=).*?(?=;)"; fileContent = Regex.Replace(fileContent, reg, value); }
這個是讀取和修改某個配置項的方法,使用正規表示式進行匹配。修改只是修改fileContent的值,並不執行儲存。
/// <summary> /// 儲存對INI檔案的修改 /// </summary> public void SaveINI() { try { fileContent = fileContent.Replace(";", newLine); //替換換行符 fileContent = EncryptionAndDecryption(fileContent); //加密 using (StreamWriter sw = new StreamWriter(filePath)) { sw.Write(fileContent); sw.Close(); } } catch (Exception ex) { throw new Exception("Save file error! Error Message:" + ex.Message); } } /// <summary> /// 加密解密演算法,使用異或演算法 /// </summary> /// <param name="str"></param> public string EncryptionAndDecryption(string str) { byte key = 32; byte[] buffer = Encoding.Default.GetBytes(str); for (int i = 0; i < buffer.Length; i++) { buffer[i] ^= key; } return Encoding.Default.GetString(buffer); }
SaveINI執行加密後儲存到ini檔案,這裡給出了簡單的對稱加密演算法,大家使用時可以使用自定義的加密演算法。
注意:笫一次讀取配置檔案由於沒有加密,呼叫瞭解密演算法,所以會出現檔案無效的異常。這裡需要先加密儲存一次,然後就好了。