INI文件是一种按照特点方式排列的文本文件。每一个INI文件构成都非常类似,由若干段落(section)组成,在每个带括号的标题下面,是若干个以单个单词开头的关键词(keyword)和一个等号,等
号右边的就是关键字对应的值(value)。其一般形式如下:1 [section1]2 keyword1=value1 3 keyword2=value24 keyword3=value35 [section2]6 keyword1=value17 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 try34 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 ///2 /// 读写INI文件的类。 3 /// 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 ///20 /// 向INI写入数据。 21 /// 22 /// 节点名。 23 /// 键名。 24 /// 值名。 25 public static void Write(string Section, string Key, string Value, string path) 26 { 27 WritePrivateProfileString(Section, Key, Value, path); 28 } 29 30 31 ///32 /// 读取INI数据。 33 /// 34 /// 节点名。 35 /// 键名。 36 /// 值名。 37 ///相应的值。 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 ///46 /// 读取一个ini里面所有的节 47 /// 48 /// 49 /// 50 ///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 /// 69 /// 得到某个节点下面所有的key和value组合 70 /// 71 /// 72 /// 73 /// 74 /// 75 ///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 ///8 /// INI文件的操作类 9 /// 10 public class IniFile11 {12 public string Path;1314 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); 2223 [DllImport("kernel32")]24 private static extern int GetPrivateProfileString(string section, string key, string defVal, StringBuilder retVal, int size, string filePath); 2526 [DllImport("kernel32")]27 private static extern int GetPrivateProfileString(string section, string key, string defVal, Byte[] retVal, int size, string filePath);28 #endregion2930 ///31 /// 写INI文件32 /// 33 /// 段落34 /// 键35 /// 值36 public void IniWriteValue(string section, string key, string iValue) 37 {38 WritePrivateProfileString(section, key, iValue, this.Path);39 }4041 ///42 /// 读取INI文件43 /// 44 /// 段落45 /// 键46 ///返回的键值 47 public string IniReadValue(string section, string key) 48 { 49 StringBuilder temp = new StringBuilder(255); 5051 int i = GetPrivateProfileString(section, key, "", temp, 255, this.Path); 52 return temp.ToString();53 }5455 ///56 /// 读取INI文件57 /// 58 /// 段,格式[]59 /// 键60 ///返回byte类型的section组或键值组 61 public byte[] IniReadValues(string section, string key)62 {63 byte[] temp = new byte[255];6465 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 = eth054 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参考: