Geeks With Blogs
Wil Peck Experience is something you get right after you need it.

Technorati Tags:

 

I recently came across a situation where I needed to check an INI file for some settings in one of my .NET apps.  I'm sure like many of you, I Google'd around and found a few solutions, many offering both read and write and most what seemed to be overly complex.  I really only needed read access, didn't care what the location was and just wanted something lightweight that could parse any INI file, including one that had comments and line breaks spread throughout with multiple sections.

Basically what I offer is two classes, one is a readonly structure providing access to the INI file data and the other is a static class used to create the readonly INI file. 

See below:

//IniFileParser.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;

namespace Configuration
{
    public static class IniFileParser
    {
        private static readonly string SectionRegexString = string.Format(@"^\[(?<{0}>.*)\].*\n(?<{1}>([^\[]|\n)*)[^\[]?$", SectionKey, DataKey);
        private static readonly string ValueRegexString = string.Format(@"^(\s)*(?<{0}>[^\=^\n]*)[\s^\n]*\=(^\s)*(?<{1}>(.*|^\n*))(\n)?$", NameKey, ValueKey);
        private const string NameKey = "Name";
        private const string ValueKey = "Value";
        private const string SectionKey = "Section";
        private const string DataKey = "Data";

        public static IniFile Parse(string iniFilePath)
        {
            if (File.Exists(iniFilePath))
            {
                StringBuilder iniFileContents = new StringBuilder();
                using (StreamReader reader = new StreamReader(iniFilePath))
                {
                    iniFileContents.Append(reader.ReadToEnd());
                }

                return new IniFile(GetSections(iniFileContents.ToString()));
            }

            return null;
        }

        private static Dictionary<string, Dictionary<string, string>> GetSections(string iniFileContents)
        {
            Dictionary<string, Dictionary<string,string>> sectionsDictionary = new Dictionary<string, Dictionary<string,string>>(StringComparer.OrdinalIgnoreCase);

            Regex sectionsRegex = new Regex(SectionRegexString,
                RegexOptions.Multiline | RegexOptions.Compiled);

            MatchCollection matches = sectionsRegex.Matches(iniFileContents);

            foreach (Match match in matches)
            {
                sectionsDictionary.Add(match.Groups[SectionKey].Value,
                    GetSectionNameValues(match.Groups[DataKey].Value));
            }

            return sectionsDictionary;
        }

        private static Dictionary<string,string> GetSectionNameValues(string sectionData)
        {
            Dictionary<string, string> sectionNameValuesDictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

            Regex nameValuesRegex = new Regex(ValueRegexString,
                RegexOptions.Compiled | RegexOptions.Multiline);

            MatchCollection matches = nameValuesRegex.Matches(sectionData);

            foreach (Match match in matches)
            {
                if (sectionNameValuesDictionary.ContainsKey(match.Groups[NameKey].Value))
                {
                    //if the value already exists, overwrite it with the new value.
                    sectionNameValuesDictionary[match.Groups[NameKey]] = match.Groups[ValueKey].Value;
                }
                else
                {
                    //add the new value.
                    sectionNameValuesDictionary.Add(match.Groups[NameKey].Value, match.Groups[ValueKey].Value);
                }
            }

            return sectionNameValuesDictionary;
        }
    }
}

//IniFile.cs

using System;
using System.Collections.Generic;

namespace Configuration
{
    public sealed class IniFile
    {
        internal IniFile(Dictionary<string, Dictionary<string,string>> sections)
        {
            _sections = sections;
        }

        private Dictionary<string, Dictionary<string,string>> _sections;

        public Dictionary<string, Dictionary<string, string>> Sections
        {
            get
            {
                return _sections;
            }
        }

        public bool HasSection(string sectionName)
        {
            return _sections.ContainsKey(sectionName);
        }

        public string[] GetSectionNames()
        {
            string[] keys = new string[_sections.Keys.Count];

            _sections.Keys.CopyTo(keys, 0);

            return keys;
        }

        public string[] GetSectionKeyNames(string sectionName)
        {
            if (HasSection(sectionName))
            {
                string[] keys = new string[_sections[sectionName].Keys.Count];

                _sections[sectionName].Keys.CopyTo(keys, 0);

                return keys;
            }
            else
            {
                throw new KeyNotFoundException("Section not found.");
            }
        }

        public string this[string sectionName, string key]
        {
            get
            {
                if (HasSection(sectionName))
                {
                    Dictionary<string,string> section = _sections[sectionName];
                    if (section.ContainsKey(key))
                    {
                        return section[key];
                    }
                    else
                    {
                        return string.Empty;
                    }
                }
                else
                {
                    return string.Empty;
                }
            }
        }
    }
}

Posted on Friday, August 8, 2008 12:41 PM .NET | Back to top


Comments on this post: .NET readonly INI file access

No comments posted yet.
Your comment:
 (will show your gravatar)


Copyright © Wil Peck | Powered by: GeeksWithBlogs.net