Read/Write Ini files Parser in VBA
Günümüzde modern yapılandırma/ayar dosyası olarak XML veya JSON kullanılıyor olsa da, bazen INI dosyalarına ihtiyaç duyulabiliyor. Konuyla ilgili VBA class modullerini kullanarak Kernel32.dll fonksiyonlarına gereksinimi olmayan nesne hazırladım.
INI dosyaları notepad uygulaması ile okunabilen bir dosyadır. Dosyayı açtığınızda aşağıdaki gibi içeriğe sahip olduğunu görürsünüz. Köşeli parantez ifadeler Section, hemen altındaki satırlar ise key=value biçimindeki verilerdir. Bazı parser'larda "=" yerine ":" kullanılabilmektedir.
[Application];Application info section Name=MyApp.exe Path=C:\ProgramFiles\MyApp [Settings];Application settings section ShowMainPage=1 FloatMenuPos=250,25
Kimilerine göre INI dosyalarıyla çalışmak gereksiz görebilirse de, bu başlık class modul ile nesne hazırlama konusunda fikir verebilir.
Aşağıdaki resimde de görüldüğü gibi VBA Parser 5 sınıftan oluşuyor. IniFile sınıfı ile yeni bir dosya oluşturulabilir veya mevcut bir dosya açılarak değiştirilerek üzerine veya farklı bir ad ile kaydedilebilir.
Dosya açarak içeriği okuma:
Sub TestOpenAndEnumarate() Dim ini As New IniFile Dim secs As Sections Dim kvps As KeyValuePairs Set secs = ini.OpenIni("C:\Windows\ODBCINST.INI") For i = 0 To secs.Count - 1 Debug.Print "["; secs.Item(i).Name; "]" Set kvps = secs.Item(i).KeyValues For j = 0 To kvps.Count - 1 Debug.Print kvps.Item(j).Key; "="; kvps.Item(j).Value Next Debug.Print Next Debug.Print 'Read specific key from spesific section 'If -Firebird/InterBase(r) driver- installed on your pc Set sec = secs.ItemByName("Firebird/InterBase(r) driver") driverName = sec.KeyValues.ItemByKey("Driver").Value Debug.Print "Returned value from ""[Firebird/InterBase(r) driver]\Driver"" => "; driverName End Sub
Varolan bir dosyayı açarak içeriği değiştirme:
Public Sub TestUpdateAndSave() Dim ini As New IniFile Dim secs As Sections Dim sec As Section Set secs = ini.OpenIni(Environ$("userprofile") & "\Desktop\MyIni.ini") 'Value update. secs.ItemByName("Menus").KeyValues.ItemByKey("File").Value = "Visible-Updated" 'Key update secs.ItemByName("Menus").KeyValues.ItemByKey("Print").Key = "PrintPreview-Updated" 'New section and add key & value Set sec = secs.Add("NewSection") sec.KeyValues.Add "NewKey", "NewValue" ini.Save Environ$("userprofile") & "\Desktop\NewMyIni.ini" 'or update it. 'ini.Save Environ$("userprofile") & "\Desktop\MyIni.ini" End Sub
Yeni bir dosya oluşturma:
Sub TestCreate() Dim ini As New IniFile Dim secs As Sections, sec As Section Set secs = ini.CreateNew Set sec = secs.Add("Settings") sec.KeyValues.Add "Color", "Red" Set sec = secs.Add("Menus") sec.KeyValues.Add "File", "Visible" sec.KeyValues.Add "Print", "Invisible" ini.Save Environ$("userprofile") & "\Desktop\MyIni.ini" End Sub
Kaynak kodlar:
1-) IniFile.cls
Private secs As Sections, m_fileName As String '/////////////////////////////////////////////////////////// '/ / '/ Author: Zeki Gürsoy - 06.01.2021 - gursoyzeki@gmail.com / '/ More information about ini files: / '/ https://en.wikipedia.org/wiki/INI_file / '/ / '/////////////////////////////////////////////////////////// Public Function OpenIni(ByVal filename As String) As Sections m_fileName = filename Call InternalLoadIni(filename) Set OpenIni = secs End Function Public Function CreateNew() As Sections m_fileName = filename Set CreateNew = secs End Function Public Sub Save(ByVal filename As String, Optional overwrite As Boolean = True) Dim stream As New ADODB.stream, stream2 As New ADODB.stream stream2.Charset = "utf-8" stream2.Type = 1 'Binary stream2.Open stream.Type = 2 'Text stream.Charset = "utf-8" stream.Open stream.WriteText ";Generated by IniFile VBA class", 1 stream.WriteText ";Create/Update at : " & Format(Now, "mm\/dd\/yyyy hh:mm:ss"), 1 stream.WriteText ";Zeki Gürsoy - 06.01.2021 - gursoyzeki@gmail.com", 1 stream.WriteText "", 1 Dim sec As Section, kvp As KeyValuePair For i = 0 To secs.Count - 1 Set sec = secs.Item(i) stream.WriteText "[" & sec.Name & "]", 1 For j = 0 To sec.KeyValues.Count - 1 Set kvp = sec.KeyValues.Item(j) stream.WriteText kvp.Key & "=" & kvp.Value, 1 Next stream.WriteText "", 1 Next stream.Position = 3 'Skip BOM stream.CopyTo stream2 stream2.SaveToFile filename, IIf(overwrite, 2, 1) stream.Flush: stream2.Flush stream.Close: stream2.Close End Sub Private Sub InternalLoadIni(ByVal filename As String) Dim textOfLine As String, secName As String, sec As Section Dim Key As String, Value As String Const SEPERATOR1 = "=" Const SEPERATOR2 = ":" Dim stream As New ADODB.stream stream.Charset = "utf-8" stream.Type = 2 stream.Open stream.LoadFromFile filename Do While Not stream.EOS textOfLine = Trim(stream.ReadText(-2)) 'Line by line Key = "": Value = "" Select Case Left(textOfLine, 1) Case ";", "#", "" 'this is a comment or variable or empty line Case "[" 'this is a section, OK rBracket = InStr(1, textOfLine, "]") secName = Mid$(textOfLine, 2, rBracket - 2) Set sec = secs.Add(secName) Case Else 'this is a key and value, OK rComment = InStr(1, textOfLine, ";") If rComment > 0 Then textOfLine = Trim$(Left$(textOfLine, rComment)) Call GetKeyValue(textOfLine, SEPERATOR1, Key, Value) 'Some implementions may use ":" seperator. 'Will try this if "=" seperator is nothing. If Key = "" Then Call GetKeyValue(textOfLine, SEPERATOR2, Key, Value) Call sec.KeyValues.Add(Key, Value) End Select Loop stream.Flush stream.Close End Sub Private Sub GetKeyValue(ByVal text As String, ByVal separator As String, ByRef Key As String, ByRef Value As String) Dim index As Integer index = InStr(1, text, separator) If index = 0 Then Exit Sub If Mid$(text, index - 1, 1) = "\" Then Exit Sub Key = Trim$(Left$(text, index - 1)) Value = Trim$(Right$(text, Len(text) - index)) End Sub Private Sub Class_Initialize() Set secs = New Sections End Sub
2-) Sections.cls
Private dic As Object, m_items, m_keys Public Function Add(ByVal sectionName As String) As Section If Not dic.Exists(sectionName) Then Dim kvc As New Section kvc.Name = sectionName Call dic.Add(sectionName, kvc) m_keys = dic.Keys m_items = dic.Items Set Add = kvc End If End Function Public Sub Remove(ByVal indexOrSectionName) If TypeName(indexOrSectionName) = "String" Then dic.Remove indexOrSectionName Else Dim k As String k = m_keys(indexOrSectionName) dic.Remove k m_keys = dic.Keys m_items = dic.Items End If End Sub Public Property Get Count() As Integer Count = dic.Count End Property Public Property Get Item(ByVal index As Integer) As Section If dic.Count > index Then Set Item = m_items(index) End If End Property Public Property Set Item(ByVal index As Integer, Value As Section) If dic.Count > index Then Dim k As String k = m_keys(index) Set dic(k) = Value End If End Property Public Property Get ItemByName(ByVal sectionName As String) As Section If dic.Exists(sectionName) Then Set ItemByName = dic(sectionName) End If End Property Public Property Set ItemByName(ByVal sectionName As String, Value As Section) If dic.Exists(sectionName) Then Set dic(sectionName) = Value End If End Property Private Sub Class_Initialize() Set dic = CreateObject("Scripting.Dictionary") dic.CompareMode = TextCompare End Sub
3-) Section.cls
Private kvps As KeyValuePairs, m_Name As String Public Property Get KeyValues() As KeyValuePairs Set KeyValues = kvps End Property Public Property Get Name() As String Name = m_Name End Property Public Property Let Name(ByVal Value As String) m_Name = Value End Property Private Sub Class_Initialize() Set kvps = New KeyValuePairs End Sub
4-) KeyValuePairs.cls
Private dic As Object, m_keys, m_items Public Function Add(ByVal vKey As String, vValue As String) As KeyValuePair If Not dic.Exists(Key) Then Dim kvp As New KeyValuePair kvp.Key = vKey kvp.Value = vValue Call dic.Add(vKey, kvp) m_keys = dic.Keys m_items = dic.Items Set Add = kvp End If End Function Public Sub Remove(ByVal indexOrKeyName) If TypeName(indexOrKeyName) = "String" Then dic.Remove indexOrKeyName Else Dim k As String k = m_keys(indexOrKeyName) dic.Remove k m_keys = dic.Keys m_items = dic.Items End If End Sub Public Property Get Count() As Integer Count = dic.Count End Property Public Property Get Item(ByVal index As Integer) As KeyValuePair If dic.Count > index Then Set Item = m_items(index) End If End Property Public Property Set Item(ByVal index As Integer, ByVal vValue As KeyValuePair) If dic.Count > index Then Dim k As String k = m_keys(index) Set dic(k) = vValue End If End Property Public Property Get ItemByKey(ByVal vKey As String) As KeyValuePair If dic.Exists(vKey) Then Set ItemByKey = dic(vKey) End If End Property Public Property Set ItemByKey(ByVal vKey As String, ByVal vValue As KeyValuePair) If dic.Exists(Key) Then Set dic(vKey) = vValue End If End Property Private Sub Class_Initialize() Set dic = CreateObject("Scripting.Dictionary") dic.CompareMode = TextCompare End Sub
5-) KeyValuePair.cls
Private m_key As String, m_value As String Public Property Get Key() As String Key = m_key End Property Public Property Let Key(ByVal vKey As String) m_key = vKey End Property Public Property Get Value() As String Value = m_value End Property Public Property Let Value(ByVal vValue As String) m_value = vValue End Property
Ne diyeyim .... hem "class" bir o kadar da "klâs" bir makale ve kod.....
YanıtlaSilTeşekkür ederim dostum. Beğendiğine sevindim.
Sil