65.9K
CodeProject 正在变化。 阅读更多。
Home

C#, VB.NET 和 VBScript 的 INI 读取/写入类

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.78/5 (53投票s)

2007年12月6日

MIT

3分钟阅读

viewsIcon

466426

downloadIcon

26788

在 VB.NET 和 VBScript 中读取和写入 INI 文件

引言

最初,这是源于 2005 年的一个 C++ 类(CIniFile)。从那时起,我重写了 CIniFile 以使其更高效。以下代码是 C++ 代码的 C#\VB.NET\VBScript 移植版本。几乎所有的类名都相同,只是去掉了开头的 "C"。当前的类名是 IniFileIniSectionIniKey

为了帮助理解如何使用代码,将演示以下语言的用法

  • C#
  • VB.NET
  • VBScript

提供了以下 Inifile 对象的源代码版本

  • C# - InifileCs.cs
  • VB.NET - InifileVb.vb
  • VBScript - IniFile.vbs

效率

在 Windows 7 运行于 Lenovo T60,拥有 2GB 内存的机器上测试时,IniFile 可以在约 2 秒内生成一个包含 10000 个节和每个节 100 个键的 ini 文件并写入磁盘。将每个节的键增加到 1000 个后,文件生成时间约为 6 秒。该文件有 10,000,000 行,大小约为 140MB。将数据从文件读回内存所花费的时间也大致相同。

[Section0]
Key0=KeyValue
Key1=KeyValue
Key2=KeyValue
...
[Section1]
Key0=KeyValue
Key1=KeyValue
Key2=KeyValue
...

解析和行为

目前,IniFile 被设计用来读取大多数 ini 文件。Ini 节应以 "[" 开头并以 "]" 结尾。 "[" 和 "]" 之间的空格将被修剪。例如,下面定义的节将被解释为 "SECTION",而不是 " SECTION "。

[          SECTION            ]
...
...
...

Ini 键/值对应有一个键值,在键值右侧用 "=" 分隔。键值也会被修剪以去除空格。例如,下面定义的键将被解释为 "MyKeyValue=SomeData"。结果的键是 "MyKeyValue",值是 "SomeData"。

[          SECTION            ]
         MyKeyValue        =SomeData
...
...

但是,Ini 键的值不会被修剪,并且会保留空格。例如,下面定义的键将被解释为 "MyIniKey= SomeDataWithSpaces "。结果的键是 "MyKeyValue",值是 " SomeDataWithSpaces "。

[          SECTION            ]
         MyKeyValue        =        SomeDataWithSpaces        
...
...

函数和返回值

// IniFile class used to read and write
// ini files by loading the file into memory
public class IniFile
{
    // Public constructor
    public IniFile()

    // Loads the Reads the data in the ini file into the IniFile object
    public void Load(string sFileName )

    // Loads the Reads the data in the ini file into the IniFile object
    public void Load(string sFileName, bool bMerge )

    // Used to save the data back to the file or your choice
    public void Save(string sFileName)

    // Gets all the sections names
    public System.Collections.ICollection Sections

    // Adds a section to the IniFile object,
    // returns a IniSection object to the new or existing object
    public IniSection AddSection(string sSection )

    // Returns true on success, removes a section
    // by its name sSection, returns trus on success
    public bool RemoveSection(string sSection)

    // Returns true on success, removes section by object, returns trus on success
    public bool RemoveSection(IniSection Section)

    // Returns true on success,
    // removes all existing sections, returns trus on success
    public bool RemoveAllSections()

    // Returns an IniSection to the section by name, NULL if it was not found
    public IniSection GetSection(string sSection)

    //  Returns a KeyValue in a certain section
    public string GetKeyValue(string sSection, string sKey)

    // Returns true on success, sets a KeyValuePair in a certain section
    public bool SetKeyValue(string sSection, string sKey, string sValue)

    // Renames an existing section returns true on success,
    // false if the section didn't exist or there
    // was another section with the same sNewSection
    public bool RenameSection(string sSection, string sNewSection)

    // Renames an existing key returns true on success,
    // false if the key didn't exist or there
    // was another section with the same sNewKey
    public bool RenameKey(string sSection, string sKey, string sNewKey)

    // IniSection class 
    public class IniSection
    {
        // Constuctor so objects are internally managed
        protected internal IniSection(IniFile parent, string sSection)

        // Returns and hashtable of keys associated with the section
        public System.Collections.ICollection Keys

        // Returns the section name
        public string Name

        // Adds a key to the IniSection object,
        // returns a IniKey object to the new or existing object
        public IniKey AddKey(string sKey)

        // Returns true on success, removes a single key by string
        public bool RemoveKey(string sKey)

        // Returns true on success, removes a single key by IniKey object
        public bool RemoveKey(IniKey Key)

        // Returns true on success, Removes all the keys in the section
        public bool RemoveAllKeys()

        // Returns a IniKey object to the key by name, NULL if it was not found
        public IniKey GetKey(string sKey)

        // Sets the section name, returns true on success, fails if the section
        // name sSection already exists
        public bool SetName(string sSection)

        // Returns the section name
        public string GetName()

        // IniKey class
        public class IniKey
        {
            // Constuctor so objects are internally managed
            protected internal IniKey(IniSection parent, string sKey)

            // Returns the name of the Key
            public string Name

            // Sets or Gets the value of the key
            public string Value

            // Sets the value of the key
            public void SetValue(string sValue)

            // Returns the value of the Key
            public string GetValue()

            // Sets the key name
            // Returns true on success,
            // fails if the section name sKey already exists
            public bool SetName(string sKey)

            // Returns the name of the Key
            public string GetName()

        } // End of IniKey class
    } // End of IniSection class
} // End of IniFile class

使用 IniFile.Sections 和 IniSection.Keys

以下代码将演示如何使用 SectionsKeys 属性

IniFile ini = new IniFile();
ini.Load("C:\\temp\\test.ini");

foreach (IniSection s in ini.Sections)
{
    Trace.WriteLine(string.Format("Section: [{0}]", s.Name));
    foreach (IniSection.IniKey k in s.Keys)
    {
        if (k.Value != string.Empty)
        {
            Trace.WriteLine(string.Format("Key: {0}={1}", k.Name, k.Value));
        }
        else
        {
            Trace.WriteLine(string.Format("Key: {0}", k.Name));
        }
    }
}

合并 INI 文件

以下代码演示了合并两个 ini 文件

IniFile ini = new IniFile();

// Load the first ini into the object
ini.Load("C:\\temp\\test1.ini");

// Load the second ini into the object
// (common section's keys will overwrite)
ini.Load("C:\\temp\\test2.ini" , true );

// Resulting combined ini
ini.Save("C:\\temp\\test1and2.ini" );

在 C# 中使用 IniFile

此代码演示了在 C# 中的用法

static void Main(string[] args)
{
    IniFile ini = new IniFile();

    // Load and existing file
    // ini.Load("C:\\temp\\ini2open.ini");

    ini.AddSection("TEST_SECTION").AddKey("Key1").Value = "Value1";
    ini.AddSection("TEST_SECTION").AddKey("Key2").Value = "Value2";
    ini.AddSection("TEST_SECTION").AddKey("Key3").Value = "Value3";
    ini.AddSection("TEST_SECTION").AddKey("Key4").Value = "Value4";
    ini.AddSection("TEST_SECTION").AddKey("Key5").Value = "Value5";
    ini.AddSection("TEST_SECTION").AddKey("Key6").Value = "Value6";
    ini.AddSection("TEST_SECTION").AddKey("Key7").Value = "Value7";

    ini.AddSection("TEST_SECTION_2").AddKey("Key1").Value = "Value1";
    ini.AddSection("TEST_SECTION_2").AddKey("Key2").Value = "Value2";
    ini.AddSection("TEST_SECTION_2").AddKey("Key3").Value = "Value3";
    ini.AddSection("TEST_SECTION_2").AddKey("Key4").Value = "Value4";
    ini.AddSection("TEST_SECTION_2").AddKey("Key5").Value = "Value5";
    ini.AddSection("TEST_SECTION_2").AddKey("Key6").Value = "Value6";
    ini.AddSection("TEST_SECTION_2").AddKey("Key7").Value = "Value7";

    // Key Rename Test
    Trace.Write("Key Rename Key1 -> KeyTemp Test: ");
    if (ini.RenameKey("TEST_SECTION", "Key1", "KeyTemp"))
        Trace.WriteLine("Pass");
    else
        Trace.WriteLine("Fail");

    // Section Rename Test
    Trace.Write("Test section rename TEST_SECTION -> TEST_SECTION_3: ");
    if (ini.RenameSection("TEST_SECTION", "TEST_SECTION_3"))
        Trace.WriteLine("Pass");
    else
        Trace.WriteLine("Fail");

    // Check Key Rename Post Section Rename
    Trace.Write("Test TEST_SECTION_3 rename key KeyTemp -> Key1: ");
    if (ini.RenameKey("TEST_SECTION_3", "KeyTemp", "Key1"))
        Trace.WriteLine("Pass");
    else
        Trace.WriteLine("Fail");

    // Check Section Rename Post Section Rename
    Trace.Write("Test section rename TEST_SECTION_3 -> TEST_SECTION: ");
    if (ini.RenameSection("TEST_SECTION_3", "TEST_SECTION"))
        Trace.WriteLine("Pass");
    else
        Trace.WriteLine("Fail");

    // Check Key Rename Key1 -> Key2 where Key2 exists
    Trace.Write("Test TEST_SECTION key rename Key1 -> Key2 where Key2 exists: ");
    if (ini.RenameKey("TEST_SECTION", "Key2", "Key1"))
        Trace.WriteLine("Pass");
    else
        Trace.WriteLine("Fail");

    // Check Key Rename
    Trace.Write("Test TEST_SECTION key rename Key2 -> Key2Renamed: ");
    if (ini.RenameKey("TEST_SECTION", "Key2", "Key2Renamed"))
        Trace.WriteLine("Pass");
    else
        Trace.WriteLine("Fail");

    // Test rename other section
    Trace.Write("Test section rename TEST_SECTION_2 -> TEST_SECTION_1 : ");
    if (ini.RenameSection("TEST_SECTION_2", "TEST_SECTION_1"))
        Trace.WriteLine("Pass");
    else
        Trace.WriteLine("Fail");

    // Check remove key
    Trace.Write("Test TEST_SECTION_1 remove key Key1: ");
    if (ini.GetSection("TEST_SECTION_1").RemoveKey("Key1"))
        Trace.WriteLine("Pass");
    else
        Trace.WriteLine("Fail");

    // Check remove key no exist
    Trace.Write("Test TEST_SECTION_1 remove key Key1: ");
    if (ini.GetSection("TEST_SECTION_1").RemoveKey("Key1"))
        Trace.WriteLine("Pass");
    else
        Trace.WriteLine("Fail");

    // Check remove section
    Trace.Write("Test remove section TEST_SECTION_1: ");
    if (ini.RemoveSection("TEST_SECTION_1"))
        Trace.WriteLine("Pass");
    else
        Trace.WriteLine("Fail");

    // Check remove section no exist
    Trace.Write("Test remove section TEST_SECTION_1: ");
    if (ini.RemoveSection("TEST_SECTION_1"))
        Trace.WriteLine("Pass");
    else
        Trace.WriteLine("Fail");

    //Save the INI
    ini.Save("C:\\temp\\test.ini");
}

在 VB.NET 中使用 IniFile

此代码演示了在 VB.NET 中的用法

Sub Main()
    Dim ini As New IniFile

    ' Load and existing file
    ' ini.Load("C:\temp\ini2open.ini")

    ini.AddSection("TEST_SECTION").AddKey("Key1").Value = "Value1"
    ini.AddSection("TEST_SECTION").AddKey("Key2").Value = "Value2"
    ini.AddSection("TEST_SECTION").AddKey("Key3").Value = "Value3"
    ini.AddSection("TEST_SECTION").AddKey("Key4").Value = "Value4"
    ini.AddSection("TEST_SECTION").AddKey("Key5").Value = "Value5"
    ini.AddSection("TEST_SECTION").AddKey("Key6").Value = "Value6"
    ini.AddSection("TEST_SECTION").AddKey("Key7").Value = "Value7"

    ini.AddSection("TEST_SECTION_2").AddKey("Key1").Value = "Value1"
    ini.AddSection("TEST_SECTION_2").AddKey("Key2").Value = "Value2"
    ini.AddSection("TEST_SECTION_2").AddKey("Key3").Value = "Value3"
    ini.AddSection("TEST_SECTION_2").AddKey("Key4").Value = "Value4"
    ini.AddSection("TEST_SECTION_2").AddKey("Key5").Value = "Value5"
    ini.AddSection("TEST_SECTION_2").AddKey("Key6").Value = "Value6"
    ini.AddSection("TEST_SECTION_2").AddKey("Key7").Value = "Value7"

    ' Key Rename Test
    Trace.Write("Key Rename Key1 -> KeyTemp Test: ")
    If ini.RenameKey("TEST_SECTION", "Key1", "KeyTemp") Then
        Trace.WriteLine("Pass") Else Trace.WriteLine("Fail")

    ' Section Rename Test
    Trace.Write("Test section rename TEST_SECTION -> TEST_SECTION_3: ")
    If ini.RenameSection("TEST_SECTION", "TEST_SECTION_3") Then
        Trace.WriteLine("Pass") Else Trace.WriteLine("Fail")

    ' Check Key Rename Post Section Rename
    Trace.Write("Test TEST_SECTION_3 rename key KeyTemp -> Key1: ")
    If ini.RenameKey("TEST_SECTION_3", "KeyTemp", "Key1") Then
        Trace.WriteLine("Pass") Else Trace.WriteLine("Fail")

    ' Check Section Rename Post Section Rename
    Trace.Write("Test section rename TEST_SECTION_3 -> TEST_SECTION: ")
    If ini.RenameSection("TEST_SECTION_3", "TEST_SECTION") Then
        Trace.WriteLine("Pass") Else Trace.WriteLine("Fail")

    ' Check Key Rename Key1 -> Key2 where Key2 exists
    Trace.Write("Test TEST_SECTION key rename Key1 -> Key2 where Key2 exists: ")
    If ini.RenameKey("TEST_SECTION", "Key2", "Key1") Then
        Trace.WriteLine("Pass") Else Trace.WriteLine("Fail")

    ' Check Key Rename
    Trace.Write("Test TEST_SECTION key rename Key2 -> Key2Renamed: ")
    If ini.RenameKey("TEST_SECTION", "Key2", "Key2Renamed") Then
        Trace.WriteLine("Pass") Else Trace.WriteLine("Fail")

    ' Test rename other section
    Trace.Write("Test section rename TEST_SECTION_2 -> TEST_SECTION_1 : ")
    If ini.RenameSection("TEST_SECTION_2", "TEST_SECTION_1") Then
        Trace.WriteLine("Pass") Else Trace.WriteLine("Fail")

    ' Check remove key
    Trace.Write("Test TEST_SECTION_1 remove key Key1: ")
    If ini.GetSection("TEST_SECTION_1").RemoveKey("Key1") Then
        Trace.WriteLine("Pass") Else Trace.WriteLine("Fail")

    ' Check remove key no exist
    Trace.Write("Test TEST_SECTION_1 remove key Key1: ")
    If ini.GetSection("TEST_SECTION_1").RemoveKey("Key1") Then
        Trace.WriteLine("Pass") Else Trace.WriteLine("Fail")

    ' Check remove section
    Trace.Write("Test remove section TEST_SECTION_1: ")
    If ini.RemoveSection("TEST_SECTION_1") Then
        Trace.WriteLine("Pass") Else Trace.WriteLine("Fail")

    ' Check remove section no exist
    Trace.Write("Test remove section TEST_SECTION_1: ")
    If ini.RemoveSection("TEST_SECTION_1") Then
        Trace.WriteLine("Pass") Else Trace.WriteLine("Fail")

    'Save the INI
    ini.Save("C:\temp\test.ini")
End Sub

在 VBScript 中使用 IniFile

此代码演示了在 VBScript 中的用法

Option Explicit

Call Main 

Sub Main()
    Dim ini

    Set ini = New IniFile

    ' Load and existing file
    'ini.Load("C:\temp\ini2open.ini", false)

    ini.AddSection("TEST_SECTION").AddKey("Key1").Value = "Value1"
    ini.AddSection("TEST_SECTION").AddKey("Key2").Value = "Value2"
    ini.AddSection("TEST_SECTION").AddKey("Key3").Value = "Value3"
    ini.AddSection("TEST_SECTION").AddKey("Key4").Value = "Value4"
    ini.AddSection("TEST_SECTION").AddKey("Key5").Value = "Value5"
    ini.AddSection("TEST_SECTION").AddKey("Key6").Value = "Value6"
    ini.AddSection("TEST_SECTION").AddKey("Key7").Value = "Value7"

    ini.AddSection("TEST_SECTION_2").AddKey("Key1").Value = "Value1"
    ini.AddSection("TEST_SECTION_2").AddKey("Key2").Value = "Value2"
    ini.AddSection("TEST_SECTION_2").AddKey("Key3").Value = "Value3"
    ini.AddSection("TEST_SECTION_2").AddKey("Key4").Value = "Value4"
    ini.AddSection("TEST_SECTION_2").AddKey("Key5").Value = "Value5"
    ini.AddSection("TEST_SECTION_2").AddKey("Key6").Value = "Value6"
    ini.AddSection("TEST_SECTION_2").AddKey("Key7").Value = "Value7"

    ' Key Rename Test
    If ini.RenameKey("TEST_SECTION","Key1","KeyTemp") Then
        WScript.Echo "Pass" Else WScript.Echo "Fail" 
    ' Section Rename Test
    If ini.RenameSection("TEST_SECTION","TEST_SECTION_3") Then
        WScript.Echo "Pass" Else WScript.Echo "Fail" 
    ' Check Key Rename Post Section Rename
    If ini.RenameKey("TEST_SECTION_3","KeyTemp","Key1") Then
        WScript.Echo "Pass" Else WScript.Echo "Fail" 
    ' Check Section Rename Post Section Rename
    If ini.RenameSection("TEST_SECTION_3","TEST_SECTION") Then
        WScript.Echo "Pass" Else WScript.Echo "Fail" 
    ' Check Fail on Conflict
    If ini.RenameKey("TEST_SECTION","Key2","Key1") Then
        WScript.Echo "Pass" Else WScript.Echo "Fail" 
    ' Check Fail on Conflict
    If ini.RenameKey("TEST_SECTION","Key2","Key2Renamed") Then
        WScript.Echo "Pass" Else WScript.Echo "Fail" 

    ' Test rename other section
    If ini.RenameSection("TEST_SECTION_2","TEST_SECTION_1") Then
        WScript.Echo "Pass" Else WScript.Echo "Fail" 
    ' Check remove key and conflict
    If ini.GetSection("TEST_SECTION_1").RemoveKey("Key1") Then
        WScript.Echo "Pass" Else WScript.Echo "Fail" 
    If ini.GetSection("TEST_SECTION_1").RemoveKey("Key1") Then
        WScript.Echo "Pass" Else WScript.Echo "Fail" 
    ' Check remove section and conflict
    If ini.RemoveSection("TEST_SECTION_1") Then
        WScript.Echo "Pass" Else WScript.Echo "Fail" 
    If ini.RemoveSection("TEST_SECTION_1") Then
        WScript.Echo "Pass" Else WScript.Echo "Fail" 

    'Save the INI
    ini.Save("C:\temp\test.ini")

End Sub

在 .NET 中使用该库

为了使用 IniFile 库,必须添加对 IniFile.dll 的引用。

历史

  • 2007 年 12 月 14 日 - 创建 - 初始 VBScript 版本
  • 2007 年 12 月 8 日 - 修复 Bug - Regex 解析字符串问题
  • 2010 年 8 月 23 日 - 创建 - 使用哈希的 C# 版本
  • 2010 年 8 月 23 日 - 创建 - 使用哈希的 VB.NET 版本
  • 2010 年 8 月 23 日 - 创建 - 使用哈希的 VBScript 版本
  • 2010 年 11 月 12 日 - 修复 Bug - 节的 Regex 匹配包含括号的键值
  • 2015 年 6 月 20 日 - 修复 Bug - 键解析 Regex 以处理名称中带空格的键
  • 2015 年 11 月 13 日 - 修复 Bug - 键解析 Regex 以处理包含多个等号的键
  • 2021 年 5 月 6 日 - 修复 Bug - 节 Regex 以读取括号内的所有内容并进行修剪(单字符问题)
© . All rights reserved.