|
Hey, nice job. I just posted an implementation I wrote a while ago on my site. It doesn't provide an interface to write to the Ini though just read from it. Take a look at it and let me know what you think.
http://www.crowsprogramming.com/archives/95
|
|
|
|
|
I added a IniGetCategories() and IniGetKeys() functions to the class based on a post I read at How to access INI Files in C# .NET - By Gerhard Stephan[^]
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Collections.Generic;
namespace Ini
{
public class IniFile
{
public string path;
[DllImport("KERNEL32.DLL", EntryPoint = "GetPrivateProfileStringW",
SetLastError=true,
CharSet=CharSet.Unicode, ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)]
private static extern int GetPrivateProfileString(
string lpAppName,
string lpKeyName,
string lpDefault,
string lpReturnString,
int nSize,
string lpFilename);
[DllImport("KERNEL32.DLL", EntryPoint="WritePrivateProfileStringW",
SetLastError=true,
CharSet=CharSet.Unicode, ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)]
private static extern int WritePrivateProfileString(
string lpAppName,
string lpKeyName,
string lpString,
string lpFilename);
public IniFile(string INIPath)
{
path = INIPath;
}
public void IniWriteValue(string Section,string Key,string Value)
{
WritePrivateProfileString(Section,Key,Value,this.path);
}
public string IniReadValue(string Section,string Key)
{
string result = new string(' ', 255);
GetPrivateProfileString(Section, Key, "", result, 255, this.path);
return result;
}
public List<string> IniGetCategories()
{
string returnString = new string(' ', 65536);
GetPrivateProfileString(null,null,null,returnString,65536,this.path);
List<string> result = new List<string>(returnString.Split('\0'));
result.RemoveRange(result.Count - 2, 2);
return result;
}
public List<string> IniGetKeys(string category)
{
string returnString = new string(' ', 32768);
GetPrivateProfileString(category, null, null, returnString, 32768, this.path);
List<string> result = new List<string>(returnString.Split('\0'));
result.RemoveRange(result.Count-2,2);
return result;
}
}
}
Hope someone finds this useful!
Ben Ethington
|
|
|
|
|
I thought i would write a quick conversion from INI to Xml based on your additions to this class.
Here is what i came up with
public static void ConvertIni2Xml(string IniFileName, string XmlOutputFileName)
{
if (string.IsNullOrEmpty(XmlOutputFileName))
{
XmlOutputFileName = Path.Combine(Path.GetDirectoryName(IniFileName), String.Format("{0}.xml", Path.GetFileNameWithoutExtension(IniFileName)));
}
IniFile iniFile = new IniFile(IniFileName);
XmlTextWriter xw = null;
try
{
xw = new XmlTextWriter(XmlOutputFileName, Encoding.UTF8);
xw.WriteStartDocument();
xw.WriteStartElement("configuration");
foreach (string categoryName in iniFile.IniGetCategories())
{
xw.WriteStartElement("category");
xw.WriteAttributeString("name", categoryName);
foreach (string keyName in iniFile.IniGetKeys(categoryName))
{
xw.WriteStartElement("setting");
xw.WriteAttributeString("name", keyName);
xw.WriteAttributeString("value", iniFile.IniReadValue(categoryName, keyName));
xw.WriteEndElement();
}
xw.WriteEndElement();
}
xw.WriteEndElement();
xw.WriteEndDocument();
}
catch (Exception)
{
throw;
}
finally
{
if (xw != null)
{
xw.Close();
}
}
}
modified on Tuesday, August 4, 2009 2:35 PM
|
|
|
|
|
Adding to Ben's changes.. here's a method for fetching all the keys and their values together. (e.g. SourceFolder=C:\Windows\Temp, DestinationFolder=E:\Audit\Archives)
public List<string> GetKeysAndValues(string section)
{
List<string> result = new List<string>();
foreach (string key in GetKeys(section))
{
result.Add(key + "=" + ReadValue(section, key));
}
return result;
}
|
|
|
|
|
This is a nice class.
I'm a C# newbie and tried to add some additional methods useful for a project of mine.
public int IniReadValue(string Section, string Key, int DefaultValue)
{
string sTemp = IniReadValue(Section, Key, "");
if (sTemp.Length == 0)
{
return DefaultValue;
}
return Int32.Parse(sTemp);
}
public ulong IniReadValue(string Section, string Key, ulong DefaultValue)
{
string sTemp = IniReadValue(Section, Key, "");
if (sTemp.Length == 0)
{
return DefaultValue;
}
return ulong.Parse(sTemp);
}
public double IniReadValue(string Section, string Key, double DefaultValue)
{
string sTemp = IniReadValue(Section, Key, "");
if (sTemp.Length == 0)
{
return DefaultValue;
}
return double.Parse(sTemp, CultureInfo.GetCultureInfo("en-US").NumberFormat);
}
public bool IniReadValue(string Section, string Key, bool DefaultValue)
{
bool RetVal = DefaultValue;
string sTemp = IniReadValue(Section, Key, "");
if (sTemp.Length == 0)
{
return DefaultValue;
}
if (!bool.TryParse(sTemp, out RetVal))
{
return (Int32.Parse(sTemp) == 0) ? false : true;
}
return RetVal;
}
|
|
|
|
|
But you defined no method to accept third parameter as string: IniReadValue(Section, Key, "")
|
|
|
|
|
It could be accomplished by modifying the original IniReadValue() method and adding a third parameter to provide a default string to be used when the searched key cannot be found.
|
|
|
|
|
I have been using this .ini class for a while in my test apps that I am developing in C#. Recently I have been building web applications using Visual Studio 2008. I have this .ini class imported into my project and it all seems to work just fine when I test the app on my computer(The one that I developed the app on) but when i publish it to the remote web server, the class does not seem to work, it does not even give me an error. are there any changes i need to make to get it to read and write an .ini file on the server that is hosting the applicaiton?
|
|
|
|
|
Excellent code, exactly what I needed ... thanks.
regards
Mark Hibbert
|
|
|
|
|
It really made my job easy.. Really appriciated!!
Clean n Neat code..!! Thanks!!
Niks
|
|
|
|
|
What are the licensing terms for this? Can I free redistribute this code as part of my products?
|
|
|
|
|
why is the path public not private?
|
|
|
|
|
Without full path, this don't create any file:
INIFile ini = new INIFile("test.ini");
This is the solution:
INIFile ini = new INIFile(".\\test.ini");
modified 15-Dec-20 21:02pm.
|
|
|
|
|
That's not completly correct.
The default path for the file is %WINDIR% (in my case C:\WINDOWS).
|
|
|
|
|
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.IO;
using System.Collections.Specialized;
namespace Utils
{
public class INIFileHandler
{
private Sections m_sections = new Sections();
private char[] vbCrLf = new char[] { '\n', '\r' };
public INIFileHandler() { }
public INIFileHandler(string strINIFile)
{
ReadFile(strINIFile);
}
public void Dispose()
{
if (m_sections != null)
m_sections = null;
}
public Sections Sections()
{
return m_sections;
}
public Section Sections(string name)
{
Section secReturn = new Section("");
try
{
secReturn = m_sections.Section(name);
}
catch (Exception ex)
{ }
if (secReturn != null)
return secReturn;
else
return new Section("");
}
public Section Sections(int index)
{
Section secReturn = new Section("");
try
{
secReturn = m_sections.Section(index);
}
catch (Exception ex)
{
}
if (secReturn != null)
return secReturn;
else
return new Section("");
}
public bool ReadFile(string strINIFile)
{
bool blnOK = false;
try
{
StreamReader srFile = File.OpenText(strINIFile);
string strFile = srFile.ReadToEnd();
string strSectionName = "";
string[] strSetting = null;
string strKey = "";
string strValue = "";
string[] strLine = strFile.Split(vbCrLf);
//~~~~~~~~~~~~~~~~~~~~~~~~
//~ Zap files
//~~~~~~~~~~~~~~~~~~~~
strFile = null;
srFile.Close();
srFile = null;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~ Loop for each line in file
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
for (int nI = 0; nI < strLine.Length; nI++)
{
if ((strLine[nI].Trim().Length > 0) && (!strLine[nI].StartsWith(";")))
{
if (strLine[nI].ToUpper().StartsWith("["))
{
strSectionName = strLine[nI].Substring(1, strLine[nI].Length - 2);
m_sections.AddSection(strSectionName);
}
else if (strSectionName.Length > 0)
{
strSetting = strLine[nI].Split('=');
strKey = strSetting[0].ToString().Trim();
strValue = strSetting[1].ToString().Trim();
m_sections.AddSetting(strKey, strValue);
}
}
}
blnOK = true;
}
catch (Exception ex)
{
blnOK = false;
}
return blnOK;
}
public bool WriteINIFile(string strFileName)
{
bool blnOK = false;
try
{
string strINIDoc = this.ToString();
if (strINIDoc != null && strINIDoc.Length > 0)
{
FileStream fs = new FileStream(strFileName, FileMode.Create, FileAccess.Write);
StreamWriter writer = new StreamWriter(fs);
writer.Write(strINIDoc);
writer.Flush();
fs.Flush();
fs.Close();
fs = null;
blnOK = true;
}
else
{
blnOK = false;
}
}
catch (Exception ex)
{
blnOK = false;
}
return blnOK;
}
public override string ToString()
{
string strReturn = "";
try
{
string strINIDoc = "";
for (int nSec = 0; nSec < m_sections.Count; nSec++)
{
strINIDoc += "[" + m_sections.Section(nSec).Name + "]" + vbCrLf;
for (int nSetting = 0; nSetting < m_sections.Section(nSec).Settings.Count; nSetting++)
{
string strSetting = m_sections.Section(nSec).Settings[nSetting];
string strKey = m_sections.Section(nSec).Keys(nSetting);
strINIDoc += strKey + "=" + strSetting + vbCrLf;
}
strINIDoc += "" + vbCrLf;
}
strReturn = strINIDoc.Trim();
}
catch (Exception ex)
{
strReturn = "";
}
return strReturn;
}
}
public class Sections : System.Collections.Specialized.NameObjectCollectionBase
{
private Section m_section;
public Sections()
{
}
public void AddSection(string name)
{
m_section = new Section(name);
base.BaseAdd(name, m_section);
}
public void AddSetting(string name, string value)
{
m_section.AddSetting(name, value);
}
public Section Section(string name)
{
return (Section)base.BaseGet(name);
}
public Section Section(int index)
{
return (Section)base.BaseGet(index);
}
}
public class Section
{
private NameValueCollection m_colSettings = new NameValueCollection();
private string m_strSectionName = "";
public Section(string name)
{
m_strSectionName = name;
}
public void Dispose()
{
if (m_colSettings != null)
{
m_colSettings = null;
}
}
public String Name
{
get
{
return m_strSectionName;
}
}
public void AddSetting(string name, string value)
{
m_colSettings.Add(name, value);
}
public System.Collections.Specialized.NameValueCollection Settings
{
get
{
return m_colSettings;
}
}
public string Setting(string name)
{
string strReturn = "";
try
{
strReturn = m_colSettings[name];
}
catch (Exception ex)
{
strReturn = "";
}
if (strReturn != null)
{
return strReturn;
}
else
{
return "";
}
}
public string Setting(int index)
{
string strReturn = "";
try
{
strReturn = m_colSettings[index];
}
catch (Exception ex)
{
strReturn = "";
}
return strReturn;
}
public string Keys(int index)
{
string strReturn = "";
try
{
strReturn = m_colSettings.GetKey(index);
}
catch (Exception ex)
{
strReturn = "";
}
if (strReturn != null)
{
return strReturn;
}
else
return "";
}
}
}
|
|
|
|
|
Could anyone tell me which are the exception i need to check in order to avoid any crash of the application when i use dll of the kernel ??
Thanks a lot
|
|
|
|
|
I've been using your code for a while in several different projects and I just realized I never thanked you for it. So... thanks!
|
|
|
|
|
at http://www.snapconfig.com
if you are working with ini files its guaranteed to make your life easier.
None
|
|
|
|
|
I had no problem getting this to work.
Very well done!
One thing I did find I needed was a way to pass a default string if the INI is empty or missing
the keyword.
This was a cinch...
public string IniReadValue(string sSection, string sKey, string sDef)
{
StringBuilder temp = new StringBuilder(255);
int i = GetPrivateProfileString ( sSection, sKey, "", temp, 255, this.path );
string sTemp = temp.ToString();
//
// If empty, put in the supplied default
if (sTemp == string.Empty)
sTemp = sDef;
//
// Return the string
return sTemp;
}
|
|
|
|
|
The third argument to GetPrivateProfileString is the default. Just pass sDef in place of "".
public string IniReadValue(string sSection, string sKey, string sDef)
{
StringBuilder temp = new StringBuilder(255);
int i = GetPrivateProfileString ( sSection, sKey, sDef, temp, 255, this.path );
return temp.ToString();
}
|
|
|
|
|