C# 操作ini文件
INI文件是一种按照特点方式排列的文本文件。每一个INI文件构成都非常类似,由若干段落(section)组成,在每个带括号的标题下面,是若干个以单个单词开头的关键词(keyword)和一个等号,等
号右边的就是关键字对应的值(value)。其一般形式如下:
1 [section1] 2 keyword1=value1 3 keyword2=value2 4 keyword3=value3 5 [section2] 6 keyword1=value1 7 keyword2=value2
1 class Program 2 3 { 4 5 [DllImport("kernel32")] 6 7 private static extern long WritePrivateProfileString (string section ,string key , string val ,string filepath); 8 9 //参数说明:section:INI文件中的段落;key:INI文件中的关键字;val:INI文件中关键字的数值;filePath:INI文件的完整的路径和名称。 10 11 [DllImport ("kernel32")] 12 13 private static extern int GetPrivateProfileString (string section , string key , string def , StringBuilder retVal , int size , string filePath ) ; 14 15 //参数说明:section:INI文件中的段落名称;key:INI文件中的关键字;def:无法读取时候时候的缺省数值;retVal:读取数值;size:数值的大小;filePath:INI文件的完整路径和名称。 16 17 public static void Main(string[] args) 18 19 { 20 21 22 23 string section="database"; 24 25 string key="sql"; 26 27 //string value="server.;database=pubs;uid=sa;pwd="; 28 29 string fileName="d:\\config.ini"; 30 31 32 33 try 34 35 { 36 37 //写入ini节点 38 39 //WritePrivateProfileString(section,key,value,fileName); 40 41 42 43 //读取ini节点 44 45 StringBuilder sb=new StringBuilder(255); 46 47 GetPrivateProfileString(section,key,"无法读取",sb,255,fileName); 48 49 50 51 Console.WriteLine(sb.ToString()); 52 53 54 55 }catch(Exception ex) 56 57 { 58 59 Console.WriteLine(ex.ToString()); 60 61 } 62 63 64 65 Console.Write("Press any key to continue . . . "); 66 67 Console.ReadKey(true); 68 69 } 70 71 72 73 }
整理出ini文件操作类:
1 /// <summary> 2 /// 读写INI文件的类。 3 /// </summary> 4 public class INIHelper 5 { 6 // 读写INI文件相关。 7 [DllImport("kernel32.dll", EntryPoint = "WritePrivateProfileString", CharSet = CharSet.Ansi)] 8 public static extern long WritePrivateProfileString(string section, string key, string val, string filePath); 9 [DllImport("kernel32.dll", EntryPoint = "GetPrivateProfileString", CharSet = CharSet.Ansi)] 10 public static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath); 11 12 [DllImport("kernel32.dll", EntryPoint = "GetPrivateProfileSectionNames", CharSet = CharSet.Ansi)] 13 public static extern int GetPrivateProfileSectionNames(IntPtr lpszReturnBuffer, int nSize, string filePath); 14 15 [DllImport("KERNEL32.DLL ", EntryPoint = "GetPrivateProfileSection", CharSet = CharSet.Ansi)] 16 public static extern int GetPrivateProfileSection(string lpAppName, byte[] lpReturnedString, int nSize, string filePath); 17 18 19 /// <summary> 20 /// 向INI写入数据。 21 /// </summary> 22 /// <PARAM name="Section">节点名。</PARAM> 23 /// <PARAM name="Key">键名。</PARAM> 24 /// <PARAM name="Value">值名。</PARAM> 25 public static void Write(string Section, string Key, string Value, string path) 26 { 27 WritePrivateProfileString(Section, Key, Value, path); 28 } 29 30 31 /// <summary> 32 /// 读取INI数据。 33 /// </summary> 34 /// <PARAM name="Section">节点名。</PARAM> 35 /// <PARAM name="Key">键名。</PARAM> 36 /// <PARAM name="Path">值名。</PARAM> 37 /// <returns>相应的值。</returns> 38 public static string Read(string Section, string Key, string path) 39 { 40 StringBuilder temp = new StringBuilder(255); 41 int i = GetPrivateProfileString(Section, Key, "", temp, 255, path); 42 return temp.ToString(); 43 } 44 45 /// <summary> 46 /// 读取一个ini里面所有的节 47 /// </summary> 48 /// <param name="sections"></param> 49 /// <param name="path"></param> 50 /// <returns></returns> 51 public static int GetAllSectionNames(out string[] sections, string path) 52 { 53 int MAX_BUFFER = 32767; 54 IntPtr pReturnedString = Marshal.AllocCoTaskMem(MAX_BUFFER); 55 int bytesReturned = GetPrivateProfileSectionNames(pReturnedString, MAX_BUFFER, path); 56 if (bytesReturned == 0) 57 { 58 sections = null; 59 return -1; 60 } 61 string local = Marshal.PtrToStringAnsi(pReturnedString, (int)bytesReturned).ToString(); 62 Marshal.FreeCoTaskMem(pReturnedString); 63 //use of Substring below removes terminating null for split 64 sections = local.Substring(0, local.Length - 1).Split('\0'); 65 return 0; 66 } 67 68 /// <summary> 69 /// 得到某个节点下面所有的key和value组合 70 /// </summary> 71 /// <param name="section"></param> 72 /// <param name="keys"></param> 73 /// <param name="values"></param> 74 /// <param name="path"></param> 75 /// <returns></returns> 76 public static int GetAllKeyValues(string section, out string[] keys, out string[] values, string path) 77 { 78 byte[] b = new byte[65535]; 79 80 GetPrivateProfileSection(section, b, b.Length, path); 81 string s = System.Text.Encoding.Default.GetString(b); 82 string[] tmp = s.Split((char)0); 83 ArrayList result = new ArrayList(); 84 foreach (string r in tmp) 85 { 86 if (r != string.Empty) 87 result.Add(r); 88 } 89 keys = new string[result.Count]; 90 values = new string[result.Count]; 91 for (int i = 0; i < result.Count; i++) 92 { 93 string[] item = result[i].ToString().Split(new char[] { '=' }); 94 if (item.Length == 2) 95 { 96 keys[i] = item[0].Trim(); 97 values[i] = item[1].Trim(); 98 } 99 else if (item.Length == 1) 100 { 101 keys[i] = item[0].Trim(); 102 values[i] = ""; 103 } 104 else if (item.Length == 0) 105 { 106 keys[i] = ""; 107 values[i] = ""; 108 } 109 } 110 111 return 0; 112 } 113 114 }
文件由若干个段落(section)组成,每个段落又分成若干个键(key)和值(value)。Windows系统自带的Win32的API函数GetPrivateProfileString()和WritePrivateProfileString()分别实现了对INI文件的读写操作,他们位于kernel32.dll下。
但是令人遗憾的是C#所使用的.NET框架下的公共类库并没有提供直接操作INI文件的类,所以唯一比较理想的方法就是调用API函数。
然后,.Net框架下的类库是基于托管代码的,而API函数是基于非托管代码的,(在运行库的控制下执行的代码称作托管代码。相反,在运行库之外运行的代码称作非托管代码。)如何实现托管代码与非托管代码之间的操作呢?.Net框架的System.Runtime.InteropServices命名空间下提供各种各样支持COM interop及平台调用服务的成员,其中最重要的属性之一DllImportAttribute可以用来定义用于访问非托管API的平台调用方法,它提供了对从非托管DLL导出的函数进行调用所必需的信息。下面就来看一下如何实现C#与API函数的互操作。
读操作:
1 [DllImport("kernel32")] 2 private static extern int GetPrivateProfileString(string section, string key, string defVal, StringBuilder retVal, int size, string filePath); 3 section:要读取的段落名 4 key: 要读取的键 5 defVal: 读取异常的情况下的缺省值 6 retVal: key所对应的值,如果该key不存在则返回空值 7 size: 值允许的大小 8 filePath: INI文件的完整路径和文件名
写操作:
1 [DllImport("kernel32")] 2 private static extern long WritePrivateProfileString(string section, string key, string val, string filePath); 3 section: 要写入的段落名 4 key: 要写入的键,如果该key存在则覆盖写入 5 val: key所对应的值 6 filePath: INI文件的完整路径和文件名
这样,在就可以使用对他们的调用,用常规的方式定义一个名为IniFile类:
1using System; 2using System.Runtime.InteropServices; 3using System.Text; 4 5namespace IPVOD.Hotel.Remoting 6{ 7 /// <summary> 8 /// INI文件的操作类 9 /// </summary> 10 public class IniFile 11 { 12 public string Path; 13 14 public IniFile(string path) 15 { 16 this.Path = path; 17 } 18 19 #region 声明读写INI文件的API函数 20 [DllImport("kernel32")] 21 private static extern long WritePrivateProfileString(string section, string key, string val, string filePath); 22 23 [DllImport("kernel32")] 24 private static extern int GetPrivateProfileString(string section, string key, string defVal, StringBuilder retVal, int size, string filePath); 25 26 [DllImport("kernel32")] 27 private static extern int GetPrivateProfileString(string section, string key, string defVal, Byte[] retVal, int size, string filePath); 28 #endregion 29 30 /// <summary> 31 /// 写INI文件 32 /// </summary> 33 /// <param name="section">段落</param> 34 /// <param name="key">键</param> 35 /// <param name="iValue">值</param> 36 public void IniWriteValue(string section, string key, string iValue) 37 { 38 WritePrivateProfileString(section, key, iValue, this.Path); 39 } 40 41 /// <summary> 42 /// 读取INI文件 43 /// </summary> 44 /// <param name="section">段落</param> 45 /// <param name="key">键</param> 46 /// <returns>返回的键值</returns> 47 public string IniReadValue(string section, string key) 48 { 49 StringBuilder temp = new StringBuilder(255); 50 51 int i = GetPrivateProfileString(section, key, "", temp, 255, this.Path); 52 return temp.ToString(); 53 } 54 55 /// <summary> 56 /// 读取INI文件 57 /// </summary> 58 /// <param name="Section">段,格式[]</param> 59 /// <param name="Key">键</param> 60 /// <returns>返回byte类型的section组或键值组</returns> 61 public byte[] IniReadValues(string section, string key) 62 { 63 byte[] temp = new byte[255]; 64 65 int i = GetPrivateProfileString(section, key, "", temp, 255, this.Path); 66 return temp; 67 } 68 } 69} 70
注意:我增加了DLL导出的函数GetPrivateProfileString的重载,说明如下:
1 [DllImport("kernel32")] 2 private static extern int GetPrivateProfileString(string section, string key, string defVal, Byte[] retVal, int size, string filePath); 3 section:要读取的段落名 4 key: 要读取的键 5 defVal: 读取异常的情况下的缺省值 6 retVal: 此参数类型不是string,而是Byte[]用于返回byte类型的section组或键值组。 7 size: 值允许的大小 8 filePath: INI文件的完整路径和文件名
1 下面看一下具体实例化IniFile类的操作: 2 3 //path为ini文件的物理路径 4 5 IniFile ini = new IniFile(path); 6 7 //读取ini文件的所有段落名 8 9 byte[] allSection = ini.IniReadValues(null, null); 10 11 12 13 通过如下方式转换byte[]类型为string[]数组类型 14 15 string[] sectionList; 16 17 ASCIIEncoding ascii = new ASCIIEncoding(); 18 19 //获取自定义设置section中的所有key,byte[]类型 20 21 sectionByte = ini.IniReadValues("personal", null); 22 23 //编码所有key的string类型 24 25 sections = ascii.GetString(sectionByte); 26 27 //获取key的数组 28 29 sectionList = sections.Split(new char[1]{'\0'}); 30 31 32 33 //读取ini文件personal段落的所有键名,返回byte[]类型 34 35 byte[] sectionByte = ini.IniReadValues("personal", null); 36 37 38 39 //读取ini文件evideo段落的MODEL键值 40 41 model = ini.IniReadValue("evideo", "MODEL"); 42 43 44 45 //将值eth0写入ini文件evideo段落的DEVICE键 46 47 ini.IniWriteValue("evideo", "DEVICE", "eth0"); 48 49 即: 50 51 [evideo] 52 53 DEVICE = eth0 54 55 56 57 //删除ini文件下personal段落下的所有键 58 59 ini.IniWriteValue("personal", null, null); 60 61 62 63 //删除ini文件下所有段落 64 65 ini.IniWriteValue(null, null, null);
创建Ini参考:http://blog.csdn.net/sdfkfkd/article/details/7050733