Click here to Skip to main content
15,879,326 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 432.1K   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

 
QuestionWriting to binary file Pin
Kishor Durve12-Jun-23 1:30
Kishor Durve12-Jun-23 1:30 
QuestionSemicolon as comment line prefix missing Pin
Member 147880292-Mar-22 8:06
Member 147880292-Mar-22 8:06 
QuestionHow to specify a default value Pin
gary hagerty29-May-20 11:14
gary hagerty29-May-20 11:14 
BugSingle Character Section not Recognized Pin
Member 1344485511-Sep-19 3:24
Member 1344485511-Sep-19 3:24 
GeneralRe: Single Character Section not Recognized Pin
Ludvik Jerabek6-May-21 8:14
Ludvik Jerabek6-May-21 8:14 
QuestionThis is Really useful but! Pin
Member 1203047119-Jul-19 8:54
Member 1203047119-Jul-19 8:54 
PraiseTHANK YOU! Pin
Member 141073523-Jan-19 9:52
Member 141073523-Jan-19 9:52 
QuestionWorks great in PowerShell Pin
jvierra2-Aug-18 1:49
jvierra2-Aug-18 1:49 
QuestionHow well does this library perform when the application crashes Pin
bmwsandman30-Aug-17 5:58
bmwsandman30-Aug-17 5:58 
Questionwhere is the inifile.dll? Pin
Member 1218348317-Aug-17 15:25
Member 1218348317-Aug-17 15:25 
PraiseThanks Pin
P. Bantle24-Feb-17 0:09
P. Bantle24-Feb-17 0:09 
QuestionDuplicate section names Pin
Martin Gossmann10-Feb-17 7:37
Martin Gossmann10-Feb-17 7:37 
QuestionSorted option for sections and keys Pin
elias pizarro8-Nov-16 6:06
elias pizarro8-Nov-16 6:06 
AnswerRe: Sorted option for sections and keys Pin
elias pizarro8-Nov-16 7:18
elias pizarro8-Nov-16 7:18 
QuestionConvert Class to VB.NET Pin
dylan666227-Oct-16 6:48
dylan666227-Oct-16 6:48 
AnswerRe: Convert Class to VB.NET Pin
elias pizarro8-Nov-16 6:03
elias pizarro8-Nov-16 6:03 
GeneralMy vote of 5 Pin
kevin.dmonte15-Apr-16 1:46
kevin.dmonte15-Apr-16 1:46 
QuestionKeys are in a different order than the file Pin
gary hagerty31-Mar-16 6:52
gary hagerty31-Mar-16 6:52 
AnswerRe: Keys are in a different order than the file Pin
Member 1257551313-Jun-16 8:11
Member 1257551313-Jun-16 8:11 
Questionhandling key values that have equal signs in them Pin
bmwsandman12-Nov-15 10:35
bmwsandman12-Nov-15 10:35 
AnswerRe: handling key values that have equal signs in them Pin
Ludvik Jerabek12-Nov-15 18:09
Ludvik Jerabek12-Nov-15 18:09 
QuestionMulti-Line values Pin
Derek Jempson28-Sep-15 3:55
Derek Jempson28-Sep-15 3:55 
AnswerRe: Multi-Line values Pin
Ludvik Jerabek28-Sep-15 8:08
Ludvik Jerabek28-Sep-15 8:08 
GeneralRe: Multi-Line values Pin
Derek Jempson28-Sep-15 8:14
Derek Jempson28-Sep-15 8:14 
GeneralMy vote of 4 Pin
Derek Jempson28-Sep-15 3:47
Derek Jempson28-Sep-15 3:47 

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.