-
Jan 23rd, 2012, 01:22 AM
#1
C# 2010 Managed INI Class
BenJones created a class to read and write INI files. I pointed out to him that there are probably better ways to write the class and to not rely on VB6 functions and routines. He sent me a PM asking me to do so, so here's the result.
This is a class written entirely without API's to read and write INI files. I honestly have no idea how successful it is in real world applications, but I tried to make it as generic/easy as possible.
It supports three types [with a fourth hidden away as private] of data:
- String
- Decimal
- Boolean
All numbers will be cast as a Decimal when read anyways, so that's why I chose to write them as Decimals.
The converted VB.net version is here.
Code:
using System;
using System.Collections.Generic;
using System.Linq;
namespace INI
{
/// <summary>
/// This exception is thrown whenever the specified section does not exist.
/// </summary>
public class SectionDoesNotExistException : Exception
{
private string _msg = string.Empty;
private string _section = string.Empty;
public override string Message
{
get { return string.Format("The section \"{0}\" does not exist!", _section); }
}
public SectionDoesNotExistException(string section)
{
_section = section;
}
}
/// <summary>
/// This exception is thrown whenever the specified field inside a section does not exist.
/// </summary>
public class FieldDoesNotExistException : Exception
{
private string _msg = string.Empty;
private string _section = string.Empty;
private string _field = string.Empty;
public override string Message
{
get { return string.Format("The field \"{0}\" does not exist in the section \"{1}\"!", _field, _section); }
}
public FieldDoesNotExistException(string section, string field)
{
_section = section;
_field = field;
}
}
/// <summary>
/// This structure contains the INI data read from the file.
/// </summary>
public struct Item
{
/// <summary>
/// The field name of this item.
/// </summary>
public string Field { get; set; }
/// <summary>
/// The value of the object.
///
/// The type of value will either be:
/// 1) String
/// 2) Boolean
/// 3) Decimal
/// </summary>
public object Value { get; set; }
}
/// <summary>
/// An easy to use, managed class to create, read, write, and modify INI files.
/// </summary>
public class Ini
{
#region Properties
/// <summary>
/// Internal use, used for making sure sections and their respective items are kept organized.
/// </summary>
private Dictionary<string, List<Item>> Items { get; set; }
/// <summary>
/// Get the different sections in the INI file.
/// </summary>
public IEnumerable<string> Sections { get { return Items.Keys.ToList(); } }
#endregion
#region Initialization and Getter
/// <summary>
/// Creates a new INI class.
/// </summary>
public Ini()
{
Items = new Dictionary<string, List<Item>>();
}
/// <summary>
/// A public accessor to retrieve items based on their section
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public List<Item> this[string name]
{
get
{
if(!SectionExists(name))
Add(name);
return Items[name];
}
set
{
if (!SectionExists(name))
Add(name);
Items[name] = value;
}
}
#endregion
#region Add & Remove
/// <summary>
/// Adds a new section to the INI file.
/// </summary>
/// <param name="section">The name of the section to add.</param>
public void Add(string section)
{
if(!SectionExists(section))
Items.Add(section, new List<Item>());
}
/// <summary>
/// Adds a new field to the INI file.
/// </summary>
/// <param name="section">The section to add the field under.</param>
/// <param name="field">The name of the field.</param>
/// <param name="value">The value to add. The value must be either a number, a boolean, or a string.</param>
public void Add(string section, string field, object value)
{
if (!SectionExists(section) || (FieldExists(section, field))) return;
this[section].Add(new Item {Field = field, Value = value});
}
/// <summary>
/// Removes a section from the INI file.
/// </summary>
/// <param name="section">The name of the section to remove.</param>
public void Remove(string section)
{
if (!SectionExists(section)) return;
Items.Remove(section);
}
/// <summary>
/// Removes a field from a specified section in the INI file.
/// </summary>
/// <param name="section">The name of the section to look under.</param>
/// <param name="field">The name of the field to remove.</param>
public void Remove(string section, string field)
{
if (!SectionExists(section) || !FieldExists(section, field)) return;
var itemList = this[section];
for (var i = 0; i < itemList.Count; i++)
{
if(itemList[i].Field.Equals(field))
{
itemList.RemoveAt(i);
}
}
this[section] = itemList;
}
#endregion
#region Existance Checking
/// <summary>
/// Checks to see if a section exists.
/// </summary>
/// <param name="section">The name of the section to check.</param>
/// <returns>Boolean</returns>
private bool SectionExists(string section)
{
return Sections.Where(sectionName => sectionName.Equals(section)).Count().Equals(1);
}
/// <summary>
/// Checks to see if a field inside of a section exists.
/// </summary>
/// <param name="section">The name of the section to check under.</param>
/// <param name="field">The name of the field to look for.</param>
/// <returns>Boolean</returns>
private bool FieldExists(string section, string field)
{
return SectionExists(section) && this[section].Where(fieldName => fieldName.Field.Equals(field)).Count().Equals(1);
}
#endregion
#region Get
/// <summary>
/// Returns the value of a field in the specified section.
/// </summary>
/// <param name="section">The specified section to look under.</param>
/// <param name="field">The field to look for.</param>
/// <returns>Object</returns>
private object GetField(string section, string field)
{
// LINQ magic.
if (SectionExists(section) && FieldExists(section, field))
{
// Grab the field and return it.
return this[section].Where(fieldName => fieldName.Field.Equals(field)).ToList()[0].Value;
}
throw new SectionDoesNotExistException(section);
}
/// <summary>
/// Returns the value of a field in the specified section as a boolean
/// </summary>
/// <param name="section">The specified section to look under.</param>
/// <param name="field">The field to look for.</param>
/// <returns>Boolean</returns>
public bool GetBooleanField(string section, string field)
{
return Convert.ToBoolean(GetField(section, field));
}
/// <summary>
/// Returns the value of a field in the specified section as a decimal.
/// </summary>
/// <param name="section">The specified section to look under.</param>
/// <param name="field">The field to look for.</param>
/// <returns>Decimal</returns>
public decimal GetNumberField(string section, string field)
{
return Convert.ToDecimal(GetField(section, field));
}
/// <summary>
/// Returns the value of a field in the specified section as a string.
/// </summary>
/// <param name="section">The specified section to look under.</param>
/// <param name="field">The field to look for.</param>
/// <returns>String</returns>
public string GetStringField(string section, string field)
{
return GetField(section, field).ToString();
}
#endregion
#region Set
/// <summary>
/// Sets the value of the specified field.
/// </summary>
/// <param name="section">The section to look under.</param>
/// <param name="field">The field to look for.</param>
/// <param name="value">The value to set.</param>
private void SetField(string section, string field, object value)
{
// Check to see that the field and section exists
if (!SectionExists(section)) throw new SectionDoesNotExistException(section);
if (!FieldExists(section, field)) throw new FieldDoesNotExistException(section, field);
// Grab the field list
var fieldList = this[section];
// Loop
for (var i = 0; i < fieldList.Count; i++)
{
//Is this it? If not, continue.
if (!fieldList[i].Field.Equals(field)) continue;
// Grab the field
var fieldData = fieldList[i];
fieldData.Value = value;
fieldList[i] = fieldData;
}
// Set it back
this[section] = fieldList;
}
/// <summary>
/// Sets the value of the specified field to a boolean value.
/// </summary>
/// <param name="section">The section to look under.</param>
/// <param name="field">The field to look for.</param>
/// <param name="value">The value to set.</param>
public void SetBooleanField(string section, string field, bool value)
{
SetField(section, field, value);
}
/// <summary>
/// Sets the value of the specified field to a numerical value.
/// </summary>
/// <param name="section">The section to look under.</param>
/// <param name="field">The field to look for.</param>
/// <param name="value">The value to set.</param>
public void SetNumberField(string section, string field, decimal value)
{
SetField(section, field, value);
}
/// <summary>
/// Sets the value of the specified field to a string value.
/// </summary>
/// <param name="section">The section to look under.</param>
/// <param name="field">The field to look for.</param>
/// <param name="value">The value to set.</param>
public void SetStringField(string section, string field, string value)
{
SetField(section, field, value);
}
#endregion
#region Save and Load
public void Load(string iniFile)
{
// Read all the lines in, remove all the blank space.
var rawFileData =
System.IO.File.ReadAllLines(iniFile).Where(line => !line.Equals(string.Empty) && !line.StartsWith(";"));
// Define a variable for use later.
var currentSection = string.Empty;
// Begin looping data!
foreach (var line in rawFileData)
{
// Check
if (line.StartsWith("["))
{
currentSection = line.TrimStart('[').TrimEnd(']');
if (!SectionExists(currentSection)) Add(currentSection);
}
else
{
// Take the item and split it.
var lineData = line.Split('=');
for (var i = 0; i < lineData.Count(); i++)
lineData[i] = lineData[i].Trim();
// Try some conversions to store the item as their natural format.
bool boolTest;
decimal numTest;
// Boolean test
if(Boolean.TryParse(lineData[1], out boolTest))
{
this[currentSection].Add(new Item { Field = lineData[0], Value = boolTest });
// Move along
continue;
}
// Number test
if (Decimal.TryParse(lineData[1], out numTest))
{
this[currentSection].Add(new Item { Field = lineData[0], Value = numTest });
// Move along
continue;
}
// It's a string, add it and keep going.
this[currentSection].Add(new Item { Field = lineData[0], Value = lineData[1] });
}
}
}
public void Save(string iniFile)
{
// Okay, create the file stream
var sw = new System.IO.StreamWriter(iniFile);
// Loop
foreach (var section in Sections)
{
// Start off each section with [sectionName]
sw.WriteLine(string.Format("[{0}]", section));
// Now get items.
var items = this[section];
// Loop and write data out.
foreach (var item in items)
sw.WriteLine("{0}={1}", item.Field, item.Value);
// Blank gap
sw.WriteLine();
}
// All done
sw.Close();
}
#endregion
}
}
Last edited by formlesstree4; Jan 23rd, 2012 at 01:31 AM.
Reason: Screwed up the getter (this[]) routine.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|