using System; using System.Text; using System.Runtime.InteropServices;namespace File.ini { public class INIFile { #region INI文件操做 /* * 針對INI文件的API操做方法,其中的節點(Section)、鍵(KEY)都不區分大小寫 * 若是指定的INI文件不存在,會自動建立該文件。 * * CharSet定義的時候使用了什麼類型,在使用相關方法時必需要使用相應的類型 * 例如 GetPrivateProfileSectionNames聲明爲CharSet.Auto,那麼就應該使用 Marshal.PtrToStringAuto來讀取相關內容 * 若是使用的是CharSet.Ansi,就應該使用Marshal.PtrToStringAnsi來讀取內容 * */ #region API聲明 /// <summary> /// 獲取全部節點名稱(Section) /// </summary> /// <param name="lpszReturnBuffer">存放節點名稱的內存地址,每一個節點之間用\0分隔</param> /// <param name="nSize">內存大小(characters)</param> /// <param name="lpFileName">Ini文件</param> /// <returns>內容的實際長度,爲0表示沒有內容,爲nSize-2表示內存大小不夠</returns> [DllImport("kernel32.dll", CharSet = CharSet.Auto)] private static extern uint GetPrivateProfileSectionNames(IntPtr lpszReturnBuffer, uint nSize, string lpFileName); /// <summary> /// 獲取某個指定節點(Section)中全部KEY和Value /// </summary> /// <param name="lpAppName">節點名稱</param> /// <param name="lpReturnedString">返回值的內存地址,每一個之間用\0分隔</param> /// <param name="nSize">內存大小(characters)</param> /// <param name="lpFileName">Ini文件</param> /// <returns>內容的實際長度,爲0表示沒有內容,爲nSize-2表示內存大小不夠</returns> [DllImport("kernel32.dll", CharSet = CharSet.Auto)] private static extern uint GetPrivateProfileSection(string lpAppName, IntPtr lpReturnedString, uint nSize, string lpFileName); /// <summary> /// 讀取INI文件中指定的Key的值 /// </summary> /// <param name="lpAppName">節點名稱。若是爲null,則讀取INI中全部節點名稱,每一個節點名稱之間用\0分隔</param> /// <param name="lpKeyName">Key名稱。若是爲null,則讀取INI中指定節點中的全部KEY,每一個KEY之間用\0分隔</param> /// <param name="lpDefault">讀取失敗時的默認值</param> /// <param name="lpReturnedString">讀取的內容緩衝區,讀取以後,多餘的地方使用\0填充</param> /// <param name="nSize">內容緩衝區的長度</param> /// <param name="lpFileName">INI文件名</param> /// <returns>實際讀取到的長度</returns> [DllImport("kernel32.dll", CharSet = CharSet.Auto)] private static extern uint GetPrivateProfileString(string lpAppName, string lpKeyName, string lpDefault, [In, Out] char[] lpReturnedString, uint nSize, string lpFileName); //另外一種聲明方式,使用 StringBuilder 做爲緩衝區類型的缺點是不能接受\0字符,會將\0及其後的字符截斷, //因此對於lpAppName或lpKeyName爲null的狀況就不適用 [DllImport("kernel32.dll", CharSet = CharSet.Auto)] private static extern uint GetPrivateProfileString(string lpAppName, string lpKeyName, string lpDefault, StringBuilder lpReturnedString, uint nSize, string lpFileName); //再一種聲明,使用string做爲緩衝區的類型同char[] [DllImport("kernel32.dll", CharSet = CharSet.Auto)] private static extern uint GetPrivateProfileString(string lpAppName, string lpKeyName, string lpDefault, string lpReturnedString, uint nSize, string lpFileName); /// <summary> /// 將指定的鍵值對寫到指定的節點,若是已經存在則替換。 /// </summary> /// <param name="lpAppName">節點,若是不存在此節點,則建立此節點</param> /// <param name="lpString">Item鍵值對,多個用\0分隔,形如key1=value1\0key2=value2 /// <para>若是爲string.Empty,則刪除指定節點下的全部內容,保留節點</para> /// <para>若是爲null,則刪除指定節點下的全部內容,而且刪除該節點</para> /// </param> /// <param name="lpFileName">INI文件</param> /// <returns>是否成功寫入</returns> [DllImport("kernel32.dll", CharSet = CharSet.Auto)] [return: MarshalAs(UnmanagedType.Bool)] //能夠沒有此行 private static extern bool WritePrivateProfileSection(string lpAppName, string lpString, string lpFileName); /// <summary> /// 將指定的鍵和值寫到指定的節點,若是已經存在則替換 /// </summary> /// <param name="lpAppName">節點名稱</param> /// <param name="lpKeyName">鍵名稱。若是爲null,則刪除指定的節點及其全部的項目</param> /// <param name="lpString">值內容。若是爲null,則刪除指定節點中指定的鍵。</param> /// <param name="lpFileName">INI文件</param> /// <returns>操做是否成功</returns> [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool WritePrivateProfileString(string lpAppName, string lpKeyName, string lpString, string lpFileName); #endregion #region 封裝 protected string iniFile; public INIFile(string iniFilePath) { iniFile = iniFilePath; } /// <summary> /// 讀取INI文件中指定INI文件中的全部節點名稱(Section) /// </summary> /// <param name="iniFile">Ini文件</param> /// <returns>全部節點,沒有內容返回string[0]</returns> public string[] GetAllSectionNames() { uint MAX_BUFFER = 32767; //默認爲32767 string[] sections = new string[0]; //返回值 //申請內存 IntPtr pReturnedString = Marshal.AllocCoTaskMem((int)MAX_BUFFER * sizeof(char)); uint bytesReturned = GetPrivateProfileSectionNames(pReturnedString, MAX_BUFFER, iniFile); if (bytesReturned != 0) { //讀取指定內存的內容 string local = Marshal.PtrToStringAuto(pReturnedString, (int)bytesReturned).ToString(); //每一個節點之間用\0分隔,末尾有一個\0 sections = local.Split(new char[] { '\0' }, StringSplitOptions.RemoveEmptyEntries); } //釋放內存 Marshal.FreeCoTaskMem(pReturnedString); return sections; } /// <summary> /// 獲取INI文件中指定節點(Section)中的全部條目(key=value形式) /// </summary> /// <param name="iniFile">Ini文件</param> /// <param name="section">節點名稱</param> /// <returns>指定節點中的全部項目,沒有內容返回string[0]</returns> public string[] GetAllItems(string section) { //返回值形式爲 key=value,例如 Color=Red uint MAX_BUFFER = 32767; //默認爲32767 string[] items = new string[0]; //返回值 //分配內存 IntPtr pReturnedString = Marshal.AllocCoTaskMem((int)MAX_BUFFER * sizeof(char)); uint bytesReturned = GetPrivateProfileSection(section, pReturnedString, MAX_BUFFER, iniFile); if (!(bytesReturned == MAX_BUFFER - 2) || (bytesReturned == 0)) { string returnedString = Marshal.PtrToStringAuto(pReturnedString, (int)bytesReturned); items = returnedString.Split(new char[] { '\0' }, StringSplitOptions.RemoveEmptyEntries); } Marshal.FreeCoTaskMem(pReturnedString); //釋放內存 return items; } /// <summary> /// 獲取INI文件中指定節點(Section)中的全部條目的Key列表 /// </summary> /// <param name="iniFile">Ini文件</param> /// <param name="section">節點名稱</param> /// <returns>若是沒有內容,反回string[0]</returns> public string[] GetAllItemKeys(string section) { string[] value = new string[0]; const int SIZE = 1024 * 10; if (string.IsNullOrEmpty(section)) { throw new ArgumentException("必須指定節點名稱", "section"); } char[] chars = new char[SIZE]; uint bytesReturned = GetPrivateProfileString(section, null, null, chars, SIZE, iniFile); if (bytesReturned != 0) { value = new string(chars).Split(new char[] { '\0' }, StringSplitOptions.RemoveEmptyEntries); } chars = null; return value; } /// <summary> /// 讀取INI文件中指定KEY的字符串型值 /// </summary> /// <param name="iniFile">Ini文件</param> /// <param name="section">節點名稱</param> /// <param name="key">鍵名稱</param> /// <param name="defaultValue">若是沒此KEY所使用的默認值</param> /// <returns>讀取到的值</returns> public string GetStringValue(string section, string key, string defaultValue) { string value = defaultValue; const int SIZE = 1024 * 10; if (string.IsNullOrEmpty(section)) { throw new ArgumentException("必須指定節點名稱", "section"); } if (string.IsNullOrEmpty(key)) { throw new ArgumentException("必須指定鍵名稱(key)", "key"); } StringBuilder sb = new StringBuilder(SIZE); uint bytesReturned = GetPrivateProfileString(section, key, defaultValue, sb, SIZE, iniFile); if (bytesReturned != 0) { value = sb.ToString(); } sb = null; return value; } /// <summary> /// 在INI文件中,將指定的鍵值對寫到指定的節點,若是已經存在則替換 /// </summary> /// <param name="iniFile">INI文件</param> /// <param name="section">節點,若是不存在此節點,則建立此節點</param> /// <param name="items">鍵值對,多個用\0分隔,形如key1=value1\0key2=value2</param> /// <returns></returns> public bool WriteItems(string section, string items) { if (string.IsNullOrEmpty(section)) { throw new ArgumentException("必須指定節點名稱", "section"); } if (string.IsNullOrEmpty(items)) { throw new ArgumentException("必須指定鍵值對", "items"); } return WritePrivateProfileSection(section, items, iniFile); } /// <summary> /// 在INI文件中,指定節點寫入指定的鍵及值。若是已經存在,則替換。若是沒有則建立。 /// </summary> /// <param name="iniFile">INI文件</param> /// <param name="section">節點</param> /// <param name="key">鍵</param> /// <param name="value">值</param> /// <returns>操做是否成功</returns> public bool WriteValue(string section, string key, string value) { if (string.IsNullOrEmpty(section)) { throw new ArgumentException("必須指定節點名稱", "section"); } if (string.IsNullOrEmpty(key)) { throw new ArgumentException("必須指定鍵名稱", "key"); } if (value == null) { throw new ArgumentException("值不能爲null", "value"); } return WritePrivateProfileString(section, key, value, iniFile); } /// <summary> /// 在INI文件中,刪除指定節點中的指定的鍵。 /// </summary> /// <param name="iniFile">INI文件</param> /// <param name="section">節點</param> /// <param name="key">鍵</param> /// <returns>操做是否成功</returns> public bool DeleteKey(string section, string key) { if (string.IsNullOrEmpty(section)) { throw new ArgumentException("必須指定節點名稱", "section"); } if (string.IsNullOrEmpty(key)) { throw new ArgumentException("必須指定鍵名稱", "key"); } return WritePrivateProfileString(section, key, null, iniFile); } /// <summary> /// 在INI文件中,刪除指定的節點。 /// </summary> /// <param name="iniFile">INI文件</param> /// <param name="section">節點</param> /// <returns>操做是否成功</returns> public bool DeleteSection(string section) { if (string.IsNullOrEmpty(section)) { throw new ArgumentException("必須指定節點名稱", "section"); } return WritePrivateProfileString(section, null, null, iniFile); } /// <summary> /// 在INI文件中,刪除指定節點中的全部內容。 /// </summary> /// <param name="iniFile">INI文件</param> /// <param name="section">節點</param> /// <returns>操做是否成功</returns> public bool EmptySection(string section) { if (string.IsNullOrEmpty(section)) { throw new ArgumentException("必須指定節點名稱", "section"); } return WritePrivateProfileSection(section, string.Empty, iniFile); } #endregion #endregion } }