-
Jan 23rd, 2012, 01:17 AM
#1
VB 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.
Anyways, this was originally written in C#, so I ran it through a conversion utility because I didn't feel like converting it by hand. I fixed up all the errors with Option Strict On & Option Infer Off, so it should work relatively well. The original C# version is located here
The class allows you to add, remove and modify fields. It's pretty easy to use.
Code:
Imports System.Collections.Generic
Imports System.Linq
''' <summary>
''' This exception is thrown whenever the specified section does not exist.
''' </summary>
Public Class SectionDoesNotExistException
Inherits Exception
Private _section As String = String.Empty
Public Overrides ReadOnly Property Message() As String
Get
Return String.Format("The section ""{0}"" does not exist!", _section)
End Get
End Property
Public Sub New(section As String)
_section = section
End Sub
End Class
''' <summary>
''' This exception is thrown whenever the specified field inside a section does not exist.
''' </summary>
Public Class FieldDoesNotExistException
Inherits Exception
Private _msg As String = String.Empty
Private _section As String = String.Empty
Private _field As String = String.Empty
Public Overrides ReadOnly Property Message() As String
Get
Return String.Format("The field ""{0}"" does not exist in the section ""{1}""!", _field, _section)
End Get
End Property
Public Sub New(section As String, field As String)
_section = section
_field = field
End Sub
End Class
''' <summary>
''' This structure contains the INI data read from the file.
''' </summary>
Public Structure Item
''' <summary>
''' The field name of this item.
''' </summary>
Public Property Field() As String
''' <summary>
''' The value of the object.
'''
''' The type of value will either be:
''' 1) String
''' 2) Boolean
''' 3) Decimal
''' </summary>
Public Property Value() As Object
End Structure
''' <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 Property Items() As Dictionary(Of String, List(Of Item))
''' <summary>
''' Get the different sections in the INI file.
''' </summary>
Public ReadOnly Property Sections() As List(Of String)
Get
Return Items.Keys.ToList()
End Get
End Property
#End Region
#Region "Initialization and Getter"
''' <summary>
''' Creates a new INI class.
''' </summary>
Public Sub New()
Items = New Dictionary(Of String, List(Of Item))()
End Sub
''' <summary>
''' A public accessor to retrieve items based on their section
''' </summary>
''' <param name="name"></param>
''' <returns></returns>
Default Public Property Item(name As String) As List(Of Item)
Get
If Not SectionExists(name) Then Add(name)
Return Items(name)
End Get
Set(value As List(Of Item))
If Not SectionExists(name) Then Add(name)
Items(name) = value
End Set
End Property
#End Region
#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 Sub Add(section As String)
If Not SectionExists(section) Then
Items.Add(section, New List(Of Item)())
End If
End Sub
''' <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 Sub Add(section As String, field As String, value As Object)
If Not SectionExists(section) OrElse (FieldExists(section, field)) Then
Return
End If
Me(section).Add(New Item() With { _
.Field = field, _
.Value = value _
})
End Sub
''' <summary>
''' Removes a section from the INI file.
''' </summary>
''' <param name="section">The name of the section to remove.</param>
Public Sub Remove(section As String)
If Not SectionExists(section) Then
Return
End If
Items.Remove(section)
End Sub
''' <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 Sub Remove(section As String, field As String)
If Not SectionExists(section) OrElse Not FieldExists(section, field) Then
Return
End If
Dim itemList As List(Of Item) = Me(section)
For i As Integer = 0 To itemList.Count - 1
If itemList(i).Field.Equals(field) Then
itemList.RemoveAt(i)
End If
Next
Me(section) = itemList
End Sub
#End Region
#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 Function SectionExists(section As String) As Boolean
Return Sections.Where(Function(sectionName) sectionName.Equals(section)).Count().Equals(1)
End Function
''' <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 Function FieldExists(section As String, field As String) As Boolean
Return SectionExists(section) AndAlso Me(section).Where(Function(fieldName) fieldName.Field.Equals(field)).Count().Equals(1)
End Function
#End Region
#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 Function GetField(section As String, field As String) As Object
' LINQ magic.
If SectionExists(section) AndAlso FieldExists(section, field) Then
' Grab the field and return it.
Return Me(section).Where(Function(fieldName) fieldName.Field.Equals(field)).ToList()(0).Value
End If
Throw New SectionDoesNotExistException(section)
End Function
''' <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 Function GetBooleanField(section As String, field As String) As Boolean
Return Convert.ToBoolean(GetField(section, field))
End Function
''' <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 Function GetNumberField(section As String, field As String) As Decimal
Return Convert.ToDecimal(GetField(section, field))
End Function
''' <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 Function GetStringField(section As String, field As String) As String
Return GetField(section, field).ToString()
End Function
#End Region
#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 Sub SetField(section As String, field As String, value As Object)
' Check to see that the field and section exists
If Not SectionExists(section) Then
Throw New SectionDoesNotExistException(section)
End If
If Not FieldExists(section, field) Then
Throw New FieldDoesNotExistException(section, field)
End If
' Grab the field list
Dim fieldList As List(Of Item) = Me(section)
' Loop
For i As Integer = 0 To fieldList.Count - 1
'Is this it? If not, continue.
If Not fieldList(i).Field.Equals(field) Then
Continue For
End If
' Grab the field
Dim fieldData As Item = fieldList(i)
fieldData.Value = value
fieldList(i) = fieldData
Next
' Set it back
Me(section) = fieldList
End Sub
''' <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 Sub SetBooleanField(section As String, field As String, value As Boolean)
SetField(section, field, value)
End Sub
''' <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 Sub SetNumberField(section As String, field As String, value As Decimal)
SetField(section, field, value)
End Sub
''' <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 Sub SetStringField(section As String, field As String, value As String)
SetField(section, field, value)
End Sub
#End Region
#Region "Save and Load"
Public Sub Load(iniFile As String)
' Read all the lines in, remove all the blank space.
Dim rawFileData As String() = IO.File.ReadAllLines(iniFile).Where(Function(line) Not line.Equals(String.Empty) AndAlso Not line.StartsWith(";")).ToArray()
' Define a variable for use later.
Dim currentSection As String = String.Empty
' Begin looping data!
For Each line As String In rawFileData
' Check
If line.StartsWith("[") Then
currentSection = line.TrimStart("["c).TrimEnd("]"c)
If Not SectionExists(currentSection) Then
Add(currentSection)
End If
Else
' Take the item and split it.
Dim lineData As List(Of String) = line.Split("="c).ToList()
For i As Integer = 0 To lineData.Count() - 1
lineData(i) = lineData(i).Trim()
Next
' Try some conversions to store the item as their natural format.
Dim boolTest As Boolean
Dim numTest As Decimal
' Boolean test
If [Boolean].TryParse(lineData(1), boolTest) Then
Me(currentSection).Add(New Item() With { _
.Field = lineData(0), _
.Value = boolTest _
})
' Move along
Continue For
End If
' Number test
If [Decimal].TryParse(lineData(1), numTest) Then
Me(currentSection).Add(New Item() With { _
.Field = lineData(0), _
.Value = numTest _
})
' Move along
Continue For
End If
' It's a string, add it and keep going.
Me(currentSection).Add(New Item() With { _
.Field = lineData(0), _
.Value = lineData(1) _
})
End If
Next
End Sub
Public Sub Save(iniFile As String)
' Okay, create the file stream
Dim sw As IO.StreamWriter = New IO.StreamWriter(iniFile)
' Loop
For Each section As String In Sections
' Start off each section with [sectionName]
sw.WriteLine(String.Format("[{0}]", section))
' Now get items.
Dim items As List(Of Item) = Me(section)
' Loop and write data out.
For Each item As Item In items
sw.WriteLine("{0}={1}", item.Field, item.Value)
Next
' Blank gap
sw.WriteLine()
Next
' All done
sw.Close()
End Sub
#End Region
End Class
Last edited by formlesstree4; Jan 23rd, 2012 at 01:32 AM.
Reason: Borked up the Default Property Item().
-
Jan 23rd, 2012, 02:50 AM
#2
Re: VB 2010 Managed INI Class
Nice example this will come in handy for my projects I know I should move to xml for storeing data but I just like old INI Files Thanks for the post
-
Sep 12th, 2012, 10:52 AM
#3
Re: VB 2010 Managed INI Class
Old thread of mine, thought I'd bump it to say the class has been upgraded and moved to Codeplex. Just grab the latest source for now until I can upload a compiled version; it has bug fixes and can save/load XML in a more generic way (AKA not using the XmlSerializer).
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
|