使用 GetPrivateProfileString 读取所有 ini 文件值

问题描述 投票:0回答:6

我需要一种方法来读取 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);

    ...
}

returnString中只是第一个键值!如何一次获取所有内容并将其写入 StringBuilder 和 List?

谢谢您的帮助!

问候莱昂22

c# stringbuilder ini
6个回答
26
投票

可能的解决方案:

[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;
}

2
投票

我相信还有

GetPrivateProfileSection()
可以提供帮助,但我同意 Zenwalker 的观点,有一些库可以帮助解决这个问题。 INI 文件并不难读:部分、键/值和注释就差不多了。


1
投票

为什么不使用 IniReader 库来读取 INI 文件?这样更容易、更快。


0
投票

这些例程将读取整个 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;
    }

0
投票
Dim MyString    As String = String.Empty
Dim BufferSize As Integer = 1024 
Dim PtrToString As IntPtr = IntPtr.Zero
Dim RetVal As Integer
RetVal = GetPrivateProfileSection(SectionName, PtrToString, BufferSize, FileNameAndPah)

如果我们的函数调用成功,我们将在 PtrToString 内存地址中获得结果,并且 RetVal 将包含 PtrToString 中字符串的长度。否则,如果该函数由于缺少足够的 BufferSize 而失败,则 RetVal 将包含 BufferSize - 2。因此我们可以检查它并使用更大的 BufferSize 再次调用该函数。

'现在,我们如何从内存地址获取字符串。

MyString = Marshal.PtrToStringAuto(PtrToString, RetVal - 1)

'这里我使用“ RetVal - 1 ”来避免额外的空字符串。

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

Dim MyStrArray() As String = MyString.Split(vbNullChar)

因此该数组包含该特定部分中的所有键值对。 并且不要忘记释放内存

Marshal.FreeHGlobal(PtrToString)

0
投票

我也需要一种方法来简单地从跨平台(Linux、Mac、Windows)的 ini 文件中读取值(不依赖于

Kernel32
GetPrivateProfileSection
)。

我最终使用了本文中的一些代码,但我将其简化了很多,并使其从 .NET Core (8.x) 控制台应用程序运行。

我还添加了一个

test.ini
文件,以便您可以下载并运行它并快速查看结果。

您可以获取一个源文件

IniFileReader.cs
并将其包含在任何项目中,以便您可以轻松地从 ini 文件中读取值。

这里是源代码的快速浏览,您可以在我的 github 存储库中获取

只需传入 ini 文件(完整路径或相对路径)并新建一个 IniFileReader,它将解析整个文件,以便您可以获取任何值或迭代它们。

class IniFileReader
{
    private string FileName {get;set;}

    private Dictionary<string, Dictionary<string, string>> m_Sections = new Dictionary<string, Dictionary<string, string>>();

    public IniFileReader(string fileName)
    {
        FileName = fileName;
        ParseFile();
    }

    public void DisplayAllSections(){
        
        foreach (string sectionKey in m_Sections.Keys){
            Console.WriteLine($"[{sectionKey}]");
            Dictionary<string,string> keyValuePairs = null;
            m_Sections.TryGetValue(sectionKey, out keyValuePairs);
            Console.WriteLine($"Values in section: {keyValuePairs.Count}");
            foreach (string k in keyValuePairs.Keys){
                 string value = null;
                 keyValuePairs.TryGetValue(k,out value);
                 Console.WriteLine($"{k} : {value}");
            }
            Console.WriteLine();
        }
    }
    private string ParseSectionName(string Line)
    {
        if (!Line.StartsWith("[")) return null;
        if (!Line.EndsWith("]")) return null;
        if (Line.Length < 3) return null;
        return Line.Substring(1, Line.Length - 2);
    }

    private bool ParseKeyValuePair(string Line, ref string Key, ref string Value)
    {
        int i;
        if ((i = Line.IndexOf('=')) <= 0) return false;
        
        int j = Line.Length - i - 1;
        Key = Line.Substring(0, i).Trim();
        if (Key.Length <= 0) return false;

        Value = (j > 0) ? (Line.Substring(i + 1, j).Trim()) : ("");
        return true;
    }

    public string GetValue(string SectionName, string Key, string DefaultValue="")
    {
        // *** Check if the section exists ***
        Dictionary<string, string> Section;
        if (!m_Sections.TryGetValue(SectionName, out Section)) return DefaultValue;

        // *** Check if the key exists ***
        string Value;
        if (!Section.TryGetValue(Key, out Value)) return DefaultValue;
    
        // *** Return the found value ***
        return Value;
    }

    public void ParseFile(){
        StreamReader sr = null;
        try
        {
            // *** Clear local cache ***
            m_Sections.Clear();

            // *** Open the INI file ***
            try
            {
                sr = new StreamReader(FileName);
            }
            catch (FileNotFoundException)
            {
                return;
            }

            Dictionary<string, string> CurrentSection = null;
            string s;
                string SectionName;
                string Key = null;
                string Value = null;
            while ((s = sr.ReadLine()) != null)
            {
                s = s.Trim();

                    SectionName = ParseSectionName(s);
                    if (SectionName != null)
                {
                    // *** Only first occurrence of a section is loaded - duplicates ignored***
                    if (m_Sections.ContainsKey(SectionName))
                    {
                        CurrentSection = null;
                    }
                    else
                    {
                        CurrentSection = new Dictionary<string, string>();
                            m_Sections.Add(SectionName, CurrentSection);
                    }
                }
                else if (CurrentSection != null)
                {
                        // *** Check for key+value pair ***
                        if (ParseKeyValuePair(s, ref Key, ref Value))
                        {
                            // *** Only first occurrence of a key is loaded - duplicates ignored ***
                            if (!CurrentSection.ContainsKey(Key))
                            {
                                CurrentSection.Add(Key, Value);
                            }
                        }
                }
            }
        }
        finally
        {
            if (sr != null) sr.Close();
            sr = null;
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.