Click here to Skip to main content
15,887,027 members
Articles / Programming Languages / C#
Article

INI Files

Rate me:
Please Sign up or sign in to vote.
4.80/5 (32 votes)
2 Jul 2008CPOL7 min read 189.4K   7.5K   81   59
Parse, manage, edit and write INI files while preserving their format. And don't get too exhausted.
; for 16-bit app support
[fonts]
[extensions]
[mci extensions]
[files]
[Mail]
MAPI=1
CMC=1
CMCDLLNAME32=mapi32.dll
CMCDLLNAME=mapi.dll
MAPIX=1
MAPIXVER=1.0.0.1
OLEMessaging=1
[MCI Extensions.BAK]
aif=MPEGVideo
aifc=MPEGVideo
aiff=MPEGVideo
asf=MPEGVideo
asx=MPEGVideo
au=MPEGVideo
m1v=MPEGVideo
...

(My win.ini)

Introduction

It is strange to write a parser of INI files each time it is needed. Why not use an existing one, especially if it is good? I give you a class library that has the following features:

  • Parses INI files using given format directions.
  • Edits them easily using one single class.
  • Automatically finds out a formatting convention.
  • Adds commentaries to the sections and values just by setting a property Comment.
  • Writes a file to the disc, preserving its original format.
  • Enjoys richly documented code.

Background

INI [=initialization] files are used to store settings that define the start-up state of some programs. Alternatively, they can just contain configuration data. Currently they can be found in special folders (desktop.ini) like "My Documents." A lot of them exist in the Windows root folder, e.g. C:\Windows\win.ini. In this article, I will use the following terminology:

[Abcd]  <- "Section"
Number=188  <- "Key" (vel "Value name") and "Value"

Using the Code

I will present three main usage guides of my library: User-Mode, Hardcore-Mode and Light-Mode.

User-Mode

The IniFile namespace contains one class: IniFile. It represents an object model of an INI file, which stores a whole structure in memory. Usage of IniFile is extremely simple.

C#
IniFile file = new IniFile();
// Adds a new section with one value

file["LastUser"]["Name"] = "Gajatko";
// Save to disc

file.Save("test.txt");

This will give the following output:

[LastUser]
Name=Gajatko

The indexer of IniFile returns an object that also has an indexer. However, it also has many other features. For example, it has a Comment property:

C#
file["LastUser"].Comment =
@"This section contains information about user
which logged in at previous program run";
file["LastUser"].SetComment("Name", "Name of user");

Result:

;This section contains information about user
;which has logged in at previous program run
[LastUser]
;Name of user
Name=Gajatko

We can freely manipulate values and sections:

C#
// Rename sections and keys

file["LastUser"].Name = "RecentUser";
file["RecentUser"].RenameKey("Name", "Login");
// Get names of all section:

string[] sections = file.GetSectionNames();
// Set existing values:

file["RecentUser"]["Login"] = "Chuck";
// Override existing comment:

file["RecentUser"].Comment = "New Comment";

Result:

;New Comment
[RecentUser]
;Name of user
Login=Chuck

Also, inline comments are supported:

C#
file["RecentUser"].InlineComment = "An inline thing";

Result:

[RecentUser]   ;An inline thing

We can save all changes to a file and read from it, as well:

C#
file.Save("test.txt");
file = IniFile.FromFile("test.txt");

More methods and properties will appear in the auto-completion service in Visual Studio. They are all commented using Summary blocks. Files edited with the IniFile class will preserve their formatting.

Concluding: the User-Mode is cool, isn't it?

Hardcore-Mode

Classes

Actually, this library contains 10 classes. The first two are implementations of StreamReader and StreamWriter:

  • IniFileReader - Reads and parses a text file.
  • IniFileWriter - Writes INI file elements to a disc.

The second group of classes is used by User-Mode:

  • IniFile - Contains the whole INI file in memory and enables easy access to it.
  • IniFileSection - Represents a section and its values.

An INI file's Elements are the core objects of the IniFiles namespace. Usually they represent single lines of a file, but sometimes more.

  • IniFileSectionStart - Represents a beginning line of a section, like "[LastUser]".
  • IniFileValue - Represents a single line with a value, like "Name=Gajatko".
  • IniFileBlankLine - Represents one or more blank lines. The actual number of them is specified in the Amount property.
  • IniFileComment - Represents one or more commentary lines.

The class IniFileElement is a base class for them all. It has standard properties that are used by Reader and Writer:

  • Line - An actual representation of the object in the INI file. The name is a little confusing because sometimes the Line contains more than one line.
  • Content - Similar to Line, but without indentation.
  • Indentation - A string of all white spaces (tabs, spaces) preceding a meaningful content.
  • Formatting - A formatting string specific to a particular type of INI file element.

IniFileSettigs is a static class that contains all format settings used by other parts of the library. Sample settings are:

  • PreserveFormatting - Default true. If set to false, the Format() method will be called for all INI file elements while writing a file. The demo shows how it works.
  • CommentChars - Array of strings that begin a comment line, by default { ";", "#" }. When adding new comments, the first string in the array is used.
  • GroupElements - As said before, when the parser runs into a multiline commentary or blank lines, it will group them into one object. Setting this property to false will prevent this practice.
  • QuoteChar - A nullable char. Default value is null, but can be set to e.g. " (double qoutation mark). Then all values will be surrounded by quotes. However, either calling the Format() method or setting PreserveFormatting to false will be necessary.
  • DefaultValueFormatting - A spectacular property that defines a default appearance of values. The default is "?=$ ;" which causes values look like this: "Key=Value ;comment".
  • ... and much more (totally 16 properties).

Usage

What can you do with the Hardcore-Mode? What can you gain?

  • Be faster.
  • Read only the values that you need.
  • Feel like a Hardcore Boss.

Sample scenario #1: You want to extract a single section from an INI file instead of loading a whole file into a dummy ConfigFile class from User-Mode. We will use IniFileReader here. Our goal is to extract the "Mail" section from win.ini to the separate file without loading all other sections.

C#
IniFileReader reader = new IniFileReader("win.ini");
// Find the section without parsing lines before it.

reader.GotoSection("Mail");
// Get section's content

List<IniFileElement> sectionElements = reader.ReadSection();
// Do not load the rest. Close the stream.

reader.Close();

// Write the section.

IniFileWriter writer = new IniFileWriter("mail.ini");
writer.WriteElements(sectionElements);
writer.Close();

A very good idea is to create an IniFile object from the extracted collection:

C#
IniFile file = IniFile.FromElements(sectionElements)

Such an IniFile would contain one section: the extracted "Mail." This enables a whole set of methods specific to User-Mode, including lazy commenting entries and easy modifying values.

Sample scenario #2: You want to get just ONE value from a file. Let's say that this value is "OLEMessaging" from the "Mail" section in win.ini.

C#
IniFileReader reader = new IniFileReader("win.ini");
reader.GotoSection("Mail");
// I do not remember how olemessaging's characters exactly look,

// so I set case-sensitivity to false (default true).

IniFileSettings.CaseSensitive = false;
IniFileValue val = reader.GotoValue("olemessaging");
reader.Close();
string oleMsg = val.Value;
// ... (do something with oleMsg).

...and so on.

Light-Mode

IniFileReader and IniFileWriter are fast. IniFile is a bit slower, although the main slowdown appears while loading a file, not performing operations. For yet higher performance, I have written an additional class in a separate namespace: IniFiles.Light.IniFileLight. It enables parsing and writing of INI files. However, it totally ignores formatting and blank lines. Everything will be written using the following pattern:

[Section]
Key=Value

It enables commenting values, but only single-line. The usage is similar to the User-Mode:

// Create a new file
Gajatko.IniFiles.Light.IniFileLight light = 
    new Gajatko.IniFiles.Light.IniFileLight();
// Set some data
light.Sections.Add("Data", new Dictionary<string, string>());
light.Sections["Data"].Add("Name", "Mickey");
light.Sections["Data"].Add("Surname", "Mouse");
// Add comments
light.Comments.Add("Data.Surname", "This is a surname");
light.Comments.Add("Data", "This is a section");
// Set a footer
light.Comments.Add("", "Footer");
// Save to a file
light.Save("light.txt");

Output:

;This is a section
[Data]
Name=Mickey
;This is a surname
Surname=Mouse
;Footer

You know the limitations of such a solution, so it's up to you which variant you use. I put the IniFileLight in a separate namespace because if somebody wants to use it, he probably wouldn't like to have all my 10 classes in the auto-completion list.

Format Preserving

Nobody forces you to use this IniFiles's skill; it can run in the background and not bother you. However, if you want to make your INI files look as originally or you are parsing ones which look as originally, I tell you that my code will not loose any content of a file. How much does the parser preserve the format? Here are some samples.

[Section1]
    Key1=  Value1

Look how Key1 looks. After the equality sign there are two spaces. If you add a new value to Section1, it will preserve this appearance and indentation:

[Section1]
    Key1=  Value1
    NewKey=  NewValue

Section1 is a little indented. If you add a new section, it will be a little indented too.

[Section1]
    Key1=  Value1
    NewKey=  NewValue
  [NewSection]

If you now add a value to Section2, it will look the same as the last value in the previous section:

[Section1]
    Key1=  Value1
    NewKey=  NewValue
  [NewSection]
    FreshKey=  FreshValue

Let's consider a section with such an appearance:

[ Section1 ]
Key1=Value1

Then a new added one will follow the template:

[ Section1 ]
Key1=Value1
[ New Section ]

Also, indentation of comments and blank lines are saved. There are situations when a conflict appears. Here is one of them: If quotes are on (IniFileSettings.QuoteChars = "\""), then we can imagine the following piece:

[Section1]
Key1="Value1" some text

It is obvious that the value of Key1 is 'Value1', not 'Value1" some text' or something like that. The parser knows that, so it interprets ' some text' as a TextOnTheRight. This also will be preserved. However, this behaviour can be changed through the IniFileSettings.AllowTextOnTheRight property.

Format preserving can be turned off by switching IniFileSettings.PreserveFormatting to false. However, you may want to save the indentation of elements. Then call the IniFile.Format(false) method to format everything excluding leading spaces, or IniFile[sectionName].Format(false) to format the specified section.

Download the demo to learn more.

Concluding

INI files are not used as often as in the old bad DOS times. Now XML is the king. However, they can still be found in various places and sometimes we have to go back to them. My library is the same for INI files as ASP is for HTML controls, where simple tags on the client side have a rich object model on the server. Being very advanced in its core gives it simple and fast access to all INI file features.

Enjoy the IniFiles library!

History

  • 21 August, 2007 -- Original version posted
  • 2 July, 2008 -- Download updated

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Poland Poland
My name is Jacek. Currently, I am a Java/kotlin developer. I like C# and Monthy Python's sense of humour.

Comments and Discussions

 
QuestionReally liked this implementation over the years. Pin
mmeents10-Dec-22 22:20
mmeents10-Dec-22 22:20 
PraiseThank you! Just what I needed! Pin
program4food27-Nov-21 8:15
program4food27-Nov-21 8:15 
Questionconfiguration (ini text) Pin
Charles Utibe David27-Aug-20 19:57
Charles Utibe David27-Aug-20 19:57 
AnswerRe: configuration (ini text) Pin
program4food27-Nov-21 8:19
program4food27-Nov-21 8:19 
GeneralMy vote of 5 Pin
zssure8-May-13 16:02
zssure8-May-13 16:02 
GeneralRe: My vote of 5 Pin
Lutosław8-May-13 22:07
Lutosław8-May-13 22:07 
QuestionCompile Error StringSplitOptions Pin
Member 838483018-Apr-12 23:38
Member 838483018-Apr-12 23:38 
QuestionCase insensitive reading Pin
wardies3-Apr-12 6:00
wardies3-Apr-12 6:00 
QuestionBlank line at the beginning of the ini file causes an error: Pin
Member 847678111-Dec-11 4:29
Member 847678111-Dec-11 4:29 
QuestionVB.NET Version? Pin
Ken Trock4-Mar-11 4:11
Ken Trock4-Mar-11 4:11 
AnswerRe: VB.NET Version? Pin
Lutosław5-Mar-11 20:47
Lutosław5-Mar-11 20:47 
Question'=' Character [modified] Pin
LouisTakePILLz23-Jan-11 18:38
LouisTakePILLz23-Jan-11 18:38 
AnswerRe: '=' Character Pin
Lutosław24-Jan-11 1:21
Lutosław24-Jan-11 1:21 
GeneralRe: '=' Character Pin
LouisTakePILLz24-Jan-11 2:46
LouisTakePILLz24-Jan-11 2:46 
GeneralRe: '=' Character Pin
Lutosław24-Jan-11 3:51
Lutosław24-Jan-11 3:51 
GeneralRe: '=' Character Pin
LouisTakePILLz25-Jan-11 2:13
LouisTakePILLz25-Jan-11 2:13 
GeneralRe: '=' Character Pin
LouisTakePILLz27-Jan-11 12:59
LouisTakePILLz27-Jan-11 12:59 
GeneralRe: '=' Character Pin
Lutosław28-Jan-11 0:57
Lutosław28-Jan-11 0:57 
GeneralRe: '=' Character Pin
Lutosław28-Jan-11 1:17
Lutosław28-Jan-11 1:17 
Generalwill this library work for a inifile without any sections Pin
kiran_sheshadri15-Feb-10 14:23
kiran_sheshadri15-Feb-10 14:23 
GeneralRe: will this library work for a inifile without any sections Pin
Lutosław16-Feb-10 21:27
Lutosław16-Feb-10 21:27 
GeneralMy vote of 1 Pin
abc@opq.com9-Dec-09 23:46
abc@opq.com9-Dec-09 23:46 
Generalsimple way :) Pin
Member 281573028-Apr-09 11:35
Member 281573028-Apr-09 11:35 
GeneralRe: simple way :) Pin
Lutosław28-Apr-09 12:01
Lutosław28-Apr-09 12:01 
AnswerRe: simple way :) Pin
Member 281573029-Apr-09 8:48
Member 281573029-Apr-09 8:48 

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.