C# 使用GetPrivateProfileString读取所有ini文件值

C# 使用GetPrivateProfileString读取所有ini文件值,c#,stringbuilder,ini,C#,Stringbuilder,Ini,我需要一种在StringBuilder变量中读取ini文件所有部分/键的方法: [DllImport("kernel32.dll")] private static extern int GetPrivateProfileString(string lpAppName, string lpKeyName, string lpDefault, StringBuilder lpReturnedString, int nSize, string lpFileName); ... private L

我需要一种在StringBuilder变量中读取ini文件所有部分/键的方法:

[DllImport("kernel32.dll")]
private static extern int GetPrivateProfileString(string lpAppName, string lpKeyName, string lpDefault, StringBuilder lpReturnedString, int nSize, string lpFileName);

...

private List<string> GetKeys(string iniFile, string category)
{
    StringBuilder returnString = new StringBuilder(255);            

    GetPrivateProfileString(category, null, null, returnString, 32768, iniFile);

    ...
}
[DllImport(“kernel32.dll”)]
私有静态外部int GetPrivateProfileString(字符串lpAppName、字符串lpKeyName、字符串lpDefault、字符串生成器lpReturnedString、int nSize、字符串lpFileName);
...
私有列表GetKey(字符串文件、字符串类别)
{
StringBuilder returnString=新的StringBuilder(255);
GetPrivateProfileString(category,null,null,returnString,32768,ini文件);
...
}
返回字符串中只有第一个键值!如何一次获取所有内容并将其写入StringBuilder和列表

谢谢你的帮助


欢迎leon22

为什么不使用InReader库来读取INI文件??这样做更简单、更快。

我相信还有
GetPrivateProfileSection()
可以提供帮助,但我同意Zenwalker的观点,有一些库可以提供帮助。INI文件并不难读:节、键/值和注释都很难读。

可能的解决方案:

[DllImport("kernel32.dll")]
private static extern int GetPrivateProfileSection(string lpAppName, byte[] lpszReturnBuffer, int nSize, string lpFileName);

private List<string> GetKeys(string iniFile, string category)
{

    byte[] buffer = new byte[2048];

    GetPrivateProfileSection(category, buffer, 2048, iniFile);
    String[] tmp = Encoding.ASCII.GetString(buffer).Trim('\0').Split('\0');

    List<string> result = new List<string>();

    foreach (String entry in tmp)
    {
        result.Add(entry.Substring(0, entry.IndexOf("=")));
    }

    return result;
}
[DllImport(“kernel32.dll”)]
private static extern int GetPrivateProfileSection(字符串lpAppName,字节[]lpszReturnBuffer,int nSize,字符串lpFileName);
私有列表GetKey(字符串文件、字符串类别)
{
字节[]缓冲区=新字节[2048];
GetPrivateProfileSection(类别,缓冲区,2048,InFile);
String[]tmp=Encoding.ASCII.GetString(buffer).Trim('\0').Split('\0');
列表结果=新列表();
foreach(tmp中的字符串条目)
{
result.Add(entry.Substring(0,entry.IndexOf(“=”));
}
返回结果;
}

这些例程将读取整个INI节,并将该节作为原始字符串的集合返回,其中每个条目都是INI文件中的一行(如果您使用INI结构,则很有用,但不一定有一个=),另一个例程将返回该节中所有条目的键值对集合

    [DllImport("kernel32.dll")]
    public static extern uint GetPrivateProfileSection(string lpAppName, IntPtr lpReturnedString, uint nSize, string lpFileName);

    // ReSharper disable once ReturnTypeCanBeEnumerable.Global
    public static string[] GetIniSectionRaw(string section, string file) {
        string[] iniLines;
        GetPrivateProfileSection(section, file, out iniLines);
        return iniLines;
    }

    /// <summary> Return an entire INI section as a list of lines.  Blank lines are ignored and all spaces around the = are also removed. </summary>
    /// <param name="section">[Section]</param>
    /// <param name="file">INI File</param>
    /// <returns> List of lines </returns>
    public static IEnumerable<KeyValuePair<string, string>> GetIniSection(string section, string file) {
        var result = new List<KeyValuePair<string, string>>();
        string[] iniLines;
        if (GetPrivateProfileSection(section, file, out iniLines)) {
            foreach (var line in iniLines) {
                var m = Regex.Match(line, @"^([^=]+)\s*=\s*(.*)");
                result.Add(m.Success
                               ? new KeyValuePair<string, string>(m.Groups[1].Value, m.Groups[2].Value)
                               : new KeyValuePair<string, string>(line, ""));
            }
        }

        return result;
    }
[DllImport(“kernel32.dll”)]
公共静态外部uint GetPrivateProfileSection(字符串lpAppName、IntPtr lpReturnedString、uint nSize、字符串lpFileName);
//ReSharper disable once ReturnTypeCanBeEnumerable.全局
公共静态字符串[]GetIniSectionRaw(字符串部分,字符串文件){
字符串行;
GetPrivateProfileSection(节、文件、输出行);
返回线;
}
///以行列表的形式返回整个INI部分。将忽略空行,并删除=周围的所有空格。
///[部分]
///INI文件
///行列表
公共静态IEnumerable GetIniSection(字符串部分,字符串文件){
var result=新列表();
字符串行;
if(GetPrivateProfileSection(节、文件、输出行)){
foreach(iniLines中的var行){
var m=Regex.Match(第行,@“^([^=]+)\s*=\s*(.*);
结果。添加(m.Success
?新的KeyValuePair(m.Groups[1]。值,m.Groups[2]。值)
:新的KeyValuePair(第“”行);
}
}
返回结果;
}
如果函数调用成功,我们将在PtrToString内存地址中获得结果,RetVal将在PtrToString中包含字符串的长度。否则,如果此函数由于缺少足够的BufferSize而失败,则RetVal将包含BufferSize-2。因此,我们可以检查它并使用更大的缓冲区大小再次调用此函数

'现在,我们可以从内存地址获取字符串

MyString = Marshal.PtrToStringAuto(PtrToString, RetVal - 1)
'这里我使用“RetVal-1”来避免额外的空字符串

'现在,我们需要拆分空字符出现的字符串

Dim MyStrArray() As String = MyString.Split(vbNullChar)
所以这个数组包含该特定部分中的所有键值对。 别忘了释放记忆

Marshal.FreeHGlobal(PtrToString)

谢谢您是否有此库的示例或链接?@zenwalker“因为它们依赖Windows API[…]”-该库使用Win32 API本身,因此速度不太可能更快。不完全正确:不是整行,只返回键(例如,带“=”的拆分没有用,因为没有返回值)。此外,它可能返回unicode字符串,因此使用0-终止符拆分无法正常工作并返回单个字符。这并不能真正回答问题,其中特别提到要使用StringBuilder类,这样我们就不必猜测最大缓冲区大小。这段代码似乎不起作用。GetIniSectionRaw从未被调用,函数的参数也不匹配。显然,此api函数比本机文件读取函数慢。我用托管代码编写了一个函数,它以3350个刻度读取整个部分。对于这段非托管代码,读取同一节需要10650个刻度。
Marshal.FreeHGlobal(PtrToString)