Click here to Skip to main content
15,868,141 members
Articles / Desktop Programming / Win32

INI Reader / Writer Class for C#, VB.NET, and VBScript

Rate me:
Please Sign up or sign in to vote.
4.78/5 (57 votes)
15 Nov 2010MIT3 min read 430.6K   26.6K   152   136
Read and write to INI files in VB.NET and VBScript

Introduction

Originally, this started out as a C++ class (CIniFile) in 2005. Since then, I rewrote CIniFile so it would be more efficient. The following code is a C#\VB.NET\VBScript port of the C++ code. Almost all the class names are the same. with the exception to the leading "C" which has been dropped. The current class names are IniFile, IniSection, and IniKey.

To help with understanding how to use the code, usage in the following languages will be demonstrated:

  • C#
  • VB.NET
  • VBScript

The following source versions of the Inifile object are provided:

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

Efficiency

During testing on Windows7 running on a Lenovo T60 w\2GB RAM, IniFile could generate an ini file holding 10000 sections with 100 keys per section and write it to disk in ~2 second(s). After increasing the keys per section to 1000, the file was generated in ~6 seconds. The file was 10,000,000 lines long, and was roughly 140MB in size. Reading the data back from the file into memory was in the same ball park.

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

Parsing and Behavior

Currently, IniFile is designed to read most ini files. Ini sections should start with a "[" and end with a "]". Whitespace between "[" and "]" will be trimmed. For example, the section defined below would be interpreted as "SECTION", not " SECTION ".

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

Ini key\value pairs should have a key value separated by an "=" to the right of the key value. Key values are also trimmed to remove whitespace. For example, the key defined below would be interpreted as "MyKeyValue=SomeData". The resulting key would be "MyKeyValue" and value would be "SomeData".

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

Ini key values, however, are not trimmed, and whitespace is preserved. For example, the key defined below would be interpreted as "MyIniKey= SomeDataWithSpaces ". The resulting key would be "MyKeyValue", and value would be " SomeDataWithSpaces ".

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

Functions and Returns

C#
// 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

Using IniFile.Sections and IniSection.Keys

The following code will demonstrate how to use the Sections and Keys properties:

C#
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));
        }
    }
}

Merging INI files

The following code demonstrates merging two ini files:

C#
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" );

Using IniFile in C#

This code demonstrates the usage in C#:

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");
}

Using IniFile in VB.NET

This code demonstrates the usage in VB.NET:

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

Using IniFile in VBScript

This code demonstrates the usage in VBScript:

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

Using the lib in .NET

In order to use the IniFile library, it is necessary to add a reference to IniFile.dll.

History

  • 12\14\2007 - Created - Initial VBScript version
  • 12\08\2007 - Bug fixed - Regex parse string issue
  • 08\23\2010 - Created - C# version which uses hashing
  • 08\23\2010 - Created - VB.NET version which uses hashing
  • 08\23\2010 - Created - VBScript version which uses hashing
  • 11\12\2010 - Bug fixed - Section regex matching on key values with brackets
  • 06\20\2015 - Bug fixed - Key parsing regex to account for keys with spaces in names
  • 11\13\2015 - Bug fixed - Key parsing regex to account for keys with multiple equals
  • 05\06\2021 - Bug fixed-  Section regex to read everything within brakets and trim (single char issue)

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Software Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralRe: Thank you! Pin
Ludvik Jerabek4-Sep-13 2:30
Ludvik Jerabek4-Sep-13 2:30 
GeneralMy vote of 5 Pin
Leecherman27-Apr-13 1:56
Leecherman27-Apr-13 1:56 
GeneralRe: My vote of 5 Pin
Ludvik Jerabek4-Sep-13 2:31
Ludvik Jerabek4-Sep-13 2:31 
NewsIMPORTANT UPDATE - Known bugs and resolutions Pin
Ludvik Jerabek21-Mar-13 13:10
Ludvik Jerabek21-Mar-13 13:10 
QuestionGrat Work Pin
Georgi K Conev11-Mar-13 9:53
Georgi K Conev11-Mar-13 9:53 
AnswerRe: Grat Work Pin
Ludvik Jerabek21-Mar-13 13:11
Ludvik Jerabek21-Mar-13 13:11 
QuestionGrat Work Pin
Georgi K Conev11-Mar-13 9:53
Georgi K Conev11-Mar-13 9:53 
GeneralMy vote of 5 Pin
Polinia9-Jan-13 0:37
Polinia9-Jan-13 0:37 
To great! Is completed Ini File.
GeneralRe: My vote of 5 Pin
Ludvik Jerabek21-Mar-13 13:11
Ludvik Jerabek21-Mar-13 13:11 
GeneralMy vote of 1 Pin
User 554965022-Nov-12 23:39
User 554965022-Nov-12 23:39 
GeneralRe: My vote of 1 Pin
Ludvik Jerabek21-Mar-13 13:13
Ludvik Jerabek21-Mar-13 13:13 
GeneralMy vote of 5 Pin
Polinia6-Oct-12 3:53
Polinia6-Oct-12 3:53 
BugKey without value invalidates the file Pin
bjuraga19-Sep-12 23:26
bjuraga19-Sep-12 23:26 
GeneralRe: Key without value invalidates the file Pin
Ludvik Jerabek20-Sep-12 3:23
Ludvik Jerabek20-Sep-12 3:23 
Questioninfo write order Pin
ggiacomoo18-Sep-12 22:51
ggiacomoo18-Sep-12 22:51 
AnswerRe: info write order Pin
Ludvik Jerabek19-Sep-12 2:12
Ludvik Jerabek19-Sep-12 2:12 
GeneralRe: info write order Pin
ggiacomoo19-Sep-12 3:24
ggiacomoo19-Sep-12 3:24 
GeneralRe: info write order Pin
chad_kidd27-Feb-14 13:18
chad_kidd27-Feb-14 13:18 
GeneralRe: info write order Pin
Daniel Kamisnki19-Aug-15 4:13
Daniel Kamisnki19-Aug-15 4:13 
GeneralRe: info write order - here's how to return a sorted list Pin
Member 1480191510-Dec-23 16:06
Member 1480191510-Dec-23 16:06 
SuggestionComment Support Pin
JoeSox30-Jun-12 3:47
JoeSox30-Jun-12 3:47 
GeneralAttaboy! :) Pin
Vitaly Tomilov10-Jun-12 3:16
Vitaly Tomilov10-Jun-12 3:16 
GeneralRe: Attaboy! :) Pin
Ludvik Jerabek10-Jun-12 4:31
Ludvik Jerabek10-Jun-12 4:31 
QuestionMultiple values for the same key? Pin
JoBrittain5-Jun-12 13:38
JoBrittain5-Jun-12 13:38 
AnswerRe: Multiple values for the same key? Pin
Ludvik Jerabek10-Jun-12 4:27
Ludvik Jerabek10-Jun-12 4:27 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.