Since I've started working with C#/.NET I've noticed that the framework doesn't appear to have built in functionality for reading windows INI files. It is of course, rather simple to create a class akin to my previous
cINIFile class in VB6 in C#, in fact, it's quite a lot easier in many ways.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace BCStartup
{
public class INIValue
{
public String Name { get; set; }
public String Value { get; set; }
public String Comment { get; set; }
public INIValue(String pName, String pValue, String pComment)
{
Name = pName;
Value = pValue;
Comment = pComment;
}
public override string ToString()
{
return Name + "=" + Value;
}
}
public class INISection
{
public String Name { get; set; }
public String Comment { get; set; }
public List<INIValue> Values { get; protected set; }
public INIValue this[String index]
{
get {
INIValue valueitem = Values.FirstOrDefault((w) => w.Name.Equals(index, StringComparison.OrdinalIgnoreCase));
if(valueitem!=null) return valueitem;
//otherwise, we add the new item...
valueitem = new INIValue(index, "", "");
Values.Add(valueitem);
return valueitem;
}
set
{
Values = Values.Where((p, x) => p.Name != index).ToList();
Values.Add(value);
}
}
public override string ToString()
{
return "[" + Name + "] (" + Values.Count().ToString() + " Values)";
}
public INISection(String pName, String pComment)
{
Name = pName;
Values = new List<INIValue>();
}
}
public class CINIFile
{
public List<INISection> Sections;
//indexer...
public INISection this[String index]
{
get {
INISection sectionitem = Sections.FirstOrDefault((w) => w.Name.Equals(index, StringComparison.OrdinalIgnoreCase));
if (sectionitem != null) return sectionitem;
//otherwise, we add the new item...
sectionitem = new INISection(index, "");
Sections.Add(sectionitem);
return sectionitem;
}
set
{
Sections = Sections.Where((p, x) => p.Name != index).ToList();
Sections.Add(value);
}
}
public CINIFile()
{
Sections = new List<INISection>();
}
public CINIFile(String filename)
{
loadINI(filename);
}
public static String findcomment(String INIfilestring)
{
bool inquote = false;
for (int i = 0; i < INIfilestring.Length; i++)
{
if (INIfilestring == '\"')
inquote = !inquote;
if (INIfilestring == ';' && !inquote)
{
return INIfilestring.Substring(i + 1);
}
}
return "";
}
public static INIValue ParseINIValue(String lineparse)
{
String parsename, parsevalue, parsecomment;
int firstequals;
parsename = lineparse.Substring(0, firstequals = lineparse.IndexOf('='));
//parsecomment = findcomment(lineparse);
///int firstequals= lineparse.IndexOf('=');
parsevalue = lineparse.Substring(firstequals + 1);
return new INIValue(parsename, parsevalue, "");
}
public void loadINI(String filename)
{
loadINI(filename, Encoding.ASCII);
}
public void loadINI(String filename, Encoding pEncoding)
{
StreamReader readstream = new StreamReader(File.OpenRead(filename), pEncoding);
loadINI(readstream);
readstream.Close();
}
public void loadINI(StreamReader readerstream)
{
INISection currsection = null;
String currentline;
Sections = new List<INISection>();
currsection = new INISection("Global", "");
Sections.Add(currsection);
while ((currentline = readerstream.ReadLine()) != null)
{
currentline = currentline.Trim();
if (!currentline.StartsWith(";"))
{
String newsectionname = null;
if (currentline.StartsWith("["))
{
newsectionname = currentline.Substring(1, currentline.IndexOf("]") - 1);
currsection = new INISection(newsectionname, findcomment(currentline));
Sections.Add(currsection);
}
else
{
//otherwise, it's likely a value.
INIValue newvalue = ParseINIValue(currentline);
currsection.Values.Add(newvalue);
}
}
else
{
//Sections.Add(new INISection("#Comment",currentline));
currsection.Values.Add(new INIValue("#Comment", "", currentline));
}
}
}
public void saveINI(String filename)
{
saveINI(filename, Encoding.ASCII);
}
public void saveINI(String filename, Encoding pEncoding)
{
StreamWriter writerstream = new StreamWriter(File.OpenWrite(filename), pEncoding);
saveINI(writerstream);
writerstream.Close();
}
public void saveINI(StreamWriter writerstream)
{
foreach (INISection currsection in Sections)
{
if (currsection.Name.Equals("#Comment"))
writerstream.WriteLine(currsection.Comment);
else
{
if (!currsection.Name.Equals("Global")) writerstream.WriteLine("[" + currsection.Name + "]");
foreach (INIValue currvalue in currsection.Values)
{
if (currvalue.Name.Equals("#Comment"))
writerstream.WriteLine(currvalue.Comment);
else
{
writerstream.WriteLine(currvalue.ToString());
}
} //foreach
} //if #comment...
} //foreach
}
}
}
paste this into a new class file (ideally, name the file CINIData.cs, but hey, I'm not here to judge.
Then, using it is simple. you can pass a filename or a StreamReader to the Constructor, or, to create a new INI file, you can not pass a file at all:
public createINIfile(String inifile)
{
CINIFile inifile = new CINIFile();
inifile["sectionname"]["valuename"].Value="This is a value";
inifile["yet another section"]["yet another val"].Value="yet one more value";
inifile.SaveINI(inifile);
}
Reading the values from an INI file is pretty similar:
public void listitemsinmainsection(String filename)
{
CINIFile ifile = new CINIFile(filename);
foreach(INIValue valueloop in ifile["main"])
{
Debug.Print("value:" + valueloop.ToString());
}
}