本来操作ini文件调用windows提供的那几个api是非常简单的事,可是在C#中用来却不见的那么 舒畅,主要是因为API调用后返回的串值上的问题. 在.net的sdk中提供的示例是用StringBuilder和IntPtr类来获取调用后返回的串值.以下是sdk 中的Buffers示例: public class LibWrap { // UINT GetSystemDirectory(LPTSTR lpBuffer, UINT uSize) [ DllImport( "Kernel32.dll", CharSet=CharSet.Auto )] public static extern int GetSystemDirectory( StringBuilder sysDirBuffer, int size ); // BOOL GetUserName(LPTSTR lpBuffer,LPDWORD nSize); [ DllImport( "Advapi32.dll", CharSet=CharSet.Auto )] public static extern bool GetUserName( StringBuilder userNameBuffer, ref int size ); // LPTSTR GetCommandLine(); [DllImport("Kernel32.dll", CharSet=CharSet.Auto)] public static extern IntPtr GetCommandLine(); } public class App { public static void Main() { // call GetSystemDirectory StringBuilder sysDirBuffer = new StringBuilder( 256 ); LibWrap.GetSystemDirectory( sysDirBuffer, sysDirBuffer.Capacity ); Console.WriteLine( "SysDir: {0}", sysDirBuffer ); // call GetUserName StringBuilder userNameBuffer = new StringBuilder( 128 ); int size = userNameBuffer.Capacity; LibWrap.GetUserName( userNameBuffer, ref size ); Console.WriteLine( "UserName: {0}", userNameBuffer ); IntPtr cmdLineStr = LibWrap.GetCommandLine(); String commandLine = Marshal.PtrToStringAuto( cmdLineStr ); Console.WriteLine( "CommandLine: {0}", commandLine ); } } 表面上以上的例子完全达到了我们的目的.可是当调用的api返回的串是用 ' /0 ' 分隔的n条串时(如下面用 到的GetPrivateProfileSectionNames和GetPrivateProfileSection)以上的方法就只能获取最前面的一条 串了,因为.net中的 Marshal类提供的方法和StringBuilder类的ToString()只是简单的截取 ' /0 ' 前的串数 据,所以后面的数据就给无辜的丢弃了. 有朋友想到了用byte数组来缓存串数据的方法 -- 分配一个很大的byte数组把数组的指针用托管的方式 封送给API(添加[MarshalAs(UnmanagedType.LPArray)]特性),再用System.Text提供字符编码转换类( ASCIIEncoding、UTF8Encoding)把byte数组里的串数据转换为String类数据.这种方法虽然实现了我们的伟 大目标,但在串的转换上却损失了不少的性能. 我个人经过一翻的探索发现一个目前来讲比较好的解决方法. 这个方法的主要思想是: 1,string类允许我们用char、sbyte类型的数据来填充构造函数,所以我们有办法预先分配一个足够的缓冲 区来存储我们要的返回串数据; 2,我们同样可以把string类型的数据的指针用托管的方式封送给API,Ansi的API添加[MarshalAs( UnmanagedType.LPStr)]特性,unicode的API添加[MarshalAs(UnmanagedType.LPWStr)]特性. 注意:如果存在unicode的API最好使用unicode的API,因为.net中的string类存储的unicode字符串且,Ansi 的API也是调用unicode的API的,所以我们直接调用unicode的API减免了CLR把Ansi字符串转换为unicode 字符串的步骤,自然性能上也就不同了. OK!下面是我实现的ini文件操作类的代码: /// <summary> /// ini文件操作类 /// </summary> public class CIni { #region 段信息的获取 //读取一个ini 文件中的所有段 [DllImport("kernel32", EntryPoint = "GetPrivateProfileSectionNamesW", CharSet= CharSet.Unicode )] private extern static int getSectionNames( [MarshalAs(UnmanagedType.LPWStr )] string szBuffer, int nlen, string filename); //读取段里的所有数据 [DllImport("kernel32",EntryPoint="GetPrivateProfileSectionW", CharSet = CharSet.Unicode)] private extern static int getSectionValues(string Section, [MarshalAs(UnmanagedType.LPWStr)] string szBuffer, int nlen, string filename); #endregion #region 键值的获取和设置 //读取键的整形值 [DllImport("kernel32",EntryPoint="GetPrivateProfileIntW" , CharSet = CharSet.Unicode)] private static extern int getKeyIntValue(string Section,string Key,int nDefault,string FileName); //读取字符串键值 [DllImport("kernel32",EntryPoint="GetPrivateProfileStringW" , CharSet = CharSet.Unicode)] private extern static int getKeyValue(string section,string key,int lpDefault, [MarshalAs(UnmanagedType.LPWStr)] string szValue, int nlen, string filename); // // //写字符串键值 [DllImport("kernel32",EntryPoint="WritePrivateProfileStringW" , CharSet = CharSet.Unicode)] private static extern bool setKeyValue(string Section,string key,string szValue,string FileName); //写段值 [DllImport("kernel32",EntryPoint ="WritePrivateProfileSectionW" , CharSet = CharSet.Unicode)] private static extern bool setSectionValue(string section,string szvalue,string filename); #endregion private static readonly char []sept={ ' /0 ' }; //分隔字符 private string m_Path=null; //ini文件路径 /// <summary> /// ini文件路径 /// </summary> public string Path { set {m_Path=value;} get {return m_Path;} } public CIni(){} public CIni(string szPath) { m_Path=szPath; } /// <summary> /// 读取所有段名 /// </summary> public string []SectionNames { get { string buffer = new string( ' /0 ' ,32768); int nlen = getSectionNames(buffer,32768-1,m_Path)-1; if (nlen >0 ) { return buffer.Substring(0,nlen).Split(sept); } return null; } } /// <summary> /// 读取段里的数据到一个字符串数组 /// </summary> /// <param name="section">段名</param> /// <param name="bufferSize">读取的数据大小(字节)</param> /// <returns>成功则不为null</returns> public string[] SectionValues(string section,int bufferSize) { string buffer = new string( ' /0 ' , bufferSize); int nlen = getSectionValues(section, buffer, bufferSize, m_Path) - 1; if (nlen > 0) { return buffer.Substring(0, nlen).Split(sept); } return null; } public string[] SectionValues(string section) { return SectionValues(section, 32768); } /// <summary> /// 从一个段中读取其 键-值 数据 /// </summary> /// <param name="section">段名</param> /// <param name="bufferSize">读取的数据大小(字节)</param> /// <returns>成功则不为null</returns> public Dictionary<string, string> SectionValuesEx(string section, int bufferSize) { string[] sztmp = SectionValues(section, bufferSize); if (sztmp !=null) { int ArrayLen=sztmp.Length; if ( ArrayLen >0) { Dictionary<string, string> dtRet = new Dictionary<string, string>(); for (int i=0;i <ArrayLen;i++) { int pos1=sztmp[i].IndexOf( ' = ' ); if (pos1 >1) { int nlen=sztmp[i].Length; // 取键名,键值 pos1++; if (pos1<nlen) dtRet.Add(sztmp[i].Substring(0, pos1-1), sztmp[i].Substring(pos1, nlen - pos1)); } } return dtRet; } } return null; } public Dictionary<string, string> SectionValuesEx(string section) { return SectionValuesEx(section, 32768); } /// <summary> /// 写一个段的数据 /// </summary> /// <param name="section"></param> /// <param name="szValue">段的数据(如果为null则删除这个段)</param> /// <returns>成功则为true</returns> public bool setSectionValue(string section,string szValue) { return setSectionValue(section,szValue,m_Path); } /// <summary> /// 读整形键值 /// </summary> /// <param name="section"></param> /// <param name="key"></param> /// <returns>成功则不为-1</returns> public int getKeyIntValue(string section,string key) { return getKeyIntValue(section,key,-1,m_Path); } /// <summary> /// 写整形键值 /// </summary> /// <param name="section"></param> /// <param name="key"></param> /// <param name="dwValue"></param> /// <returns>成功则为true</returns> public bool setKeyIntValue(string section,string key,int dwValue) { return setKeyValue(section,key,dwValue.ToString(),m_Path); } /// <summary> /// 读取键值 /// </summary> /// <param name="section"></param> /// <param name="key"></param> /// <returns>成功则不为null</returns> public string getKeyValue(string section,string key) { string szBuffer=new string ( ' 0 ' ,256); int nlen=getKeyValue(section,key,0, szBuffer,256,m_Path); return szBuffer.Substring(0,nlen-1); } /// <summary> /// 写字符串键值 /// </summary> /// <param name="Section"></param> /// <param name="key"></param> /// <param name="szValue"></param> /// <returns>成功则为true</returns> public bool setKeyValue(string Section ,string key,string szValue) { return setKeyValue(Section,key,szValue,m_Path); } }//end class CIni CIni类的使用示例