C#, VB.NET 和 VBScript 的 INI 读取/写入类






4.78/5 (53投票s)
在 VB.NET 和 VBScript 中读取和写入 INI 文件
引言
最初,这是源于 2005 年的一个 C++ 类(CIniFile)。从那时起,我重写了 CIniFile
以使其更高效。以下代码是 C++ 代码的 C#\VB.NET\VBScript 移植版本。几乎所有的类名都相同,只是去掉了开头的 "C"。当前的类名是 IniFile
、IniSection
和 IniKey
。
为了帮助理解如何使用代码,将演示以下语言的用法
- C#
- VB.NET
- VBScript
提供了以下 Inifile
对象的源代码版本
- C# - InifileCs.cs
- VB.NET - InifileVb.vb
- VBScript - IniFile.vbs
效率
在 Windows 7 运行于 Lenovo T60,拥有 2GB 内存的机器上测试时,IniFile
可以在约 2 秒内生成一个包含 10000 个节和每个节 100 个键的 ini 文件并写入磁盘。将每个节的键增加到 1000 个后,文件生成时间约为 6 秒。该文件有 10,000,000 行,大小约为 140MB。将数据从文件读回内存所花费的时间也大致相同。
[Section0]
Key0=KeyValue
Key1=KeyValue
Key2=KeyValue
...
[Section1]
Key0=KeyValue
Key1=KeyValue
Key2=KeyValue
...
解析和行为
目前,IniFile
被设计用来读取大多数 ini 文件。Ini 节应以 "[" 开头并以 "]" 结尾。 "[" 和 "]" 之间的空格将被修剪。例如,下面定义的节将被解释为 "SECTION
",而不是 " SECTION
"。
[ SECTION ]
...
...
...
Ini 键/值对应有一个键值,在键值右侧用 "=" 分隔。键值也会被修剪以去除空格。例如,下面定义的键将被解释为 "MyKeyValue=SomeData
"。结果的键是 "MyKeyValue
",值是 "SomeData
"。
[ SECTION ]
MyKeyValue =SomeData
...
...
但是,Ini 键的值不会被修剪,并且会保留空格。例如,下面定义的键将被解释为 "MyIniKey= SomeDataWithSpaces
"。结果的键是 "MyKeyValue
",值是 " SomeDataWithSpaces
"。
[ SECTION ]
MyKeyValue = SomeDataWithSpaces
...
...
函数和返回值
// IniFile class used to read and write
// ini files by loading the file into memory
public class IniFile
{
// Public constructor
public IniFile()
// Loads the Reads the data in the ini file into the IniFile object
public void Load(string sFileName )
// Loads the Reads the data in the ini file into the IniFile object
public void Load(string sFileName, bool bMerge )
// Used to save the data back to the file or your choice
public void Save(string sFileName)
// Gets all the sections names
public System.Collections.ICollection Sections
// Adds a section to the IniFile object,
// returns a IniSection object to the new or existing object
public IniSection AddSection(string sSection )
// Returns true on success, removes a section
// by its name sSection, returns trus on success
public bool RemoveSection(string sSection)
// Returns true on success, removes section by object, returns trus on success
public bool RemoveSection(IniSection Section)
// Returns true on success,
// removes all existing sections, returns trus on success
public bool RemoveAllSections()
// Returns an IniSection to the section by name, NULL if it was not found
public IniSection GetSection(string sSection)
// Returns a KeyValue in a certain section
public string GetKeyValue(string sSection, string sKey)
// Returns true on success, sets a KeyValuePair in a certain section
public bool SetKeyValue(string sSection, string sKey, string sValue)
// Renames an existing section returns true on success,
// false if the section didn't exist or there
// was another section with the same sNewSection
public bool RenameSection(string sSection, string sNewSection)
// Renames an existing key returns true on success,
// false if the key didn't exist or there
// was another section with the same sNewKey
public bool RenameKey(string sSection, string sKey, string sNewKey)
// IniSection class
public class IniSection
{
// Constuctor so objects are internally managed
protected internal IniSection(IniFile parent, string sSection)
// Returns and hashtable of keys associated with the section
public System.Collections.ICollection Keys
// Returns the section name
public string Name
// Adds a key to the IniSection object,
// returns a IniKey object to the new or existing object
public IniKey AddKey(string sKey)
// Returns true on success, removes a single key by string
public bool RemoveKey(string sKey)
// Returns true on success, removes a single key by IniKey object
public bool RemoveKey(IniKey Key)
// Returns true on success, Removes all the keys in the section
public bool RemoveAllKeys()
// Returns a IniKey object to the key by name, NULL if it was not found
public IniKey GetKey(string sKey)
// Sets the section name, returns true on success, fails if the section
// name sSection already exists
public bool SetName(string sSection)
// Returns the section name
public string GetName()
// IniKey class
public class IniKey
{
// Constuctor so objects are internally managed
protected internal IniKey(IniSection parent, string sKey)
// Returns the name of the Key
public string Name
// Sets or Gets the value of the key
public string Value
// Sets the value of the key
public void SetValue(string sValue)
// Returns the value of the Key
public string GetValue()
// Sets the key name
// Returns true on success,
// fails if the section name sKey already exists
public bool SetName(string sKey)
// Returns the name of the Key
public string GetName()
} // End of IniKey class
} // End of IniSection class
} // End of IniFile class
使用 IniFile.Sections 和 IniSection.Keys
以下代码将演示如何使用 Sections
和 Keys
属性
IniFile ini = new IniFile();
ini.Load("C:\\temp\\test.ini");
foreach (IniSection s in ini.Sections)
{
Trace.WriteLine(string.Format("Section: [{0}]", s.Name));
foreach (IniSection.IniKey k in s.Keys)
{
if (k.Value != string.Empty)
{
Trace.WriteLine(string.Format("Key: {0}={1}", k.Name, k.Value));
}
else
{
Trace.WriteLine(string.Format("Key: {0}", k.Name));
}
}
}
合并 INI 文件
以下代码演示了合并两个 ini 文件
IniFile ini = new IniFile();
// Load the first ini into the object
ini.Load("C:\\temp\\test1.ini");
// Load the second ini into the object
// (common section's keys will overwrite)
ini.Load("C:\\temp\\test2.ini" , true );
// Resulting combined ini
ini.Save("C:\\temp\\test1and2.ini" );
在 C# 中使用 IniFile
此代码演示了在 C# 中的用法
static void Main(string[] args)
{
IniFile ini = new IniFile();
// Load and existing file
// ini.Load("C:\\temp\\ini2open.ini");
ini.AddSection("TEST_SECTION").AddKey("Key1").Value = "Value1";
ini.AddSection("TEST_SECTION").AddKey("Key2").Value = "Value2";
ini.AddSection("TEST_SECTION").AddKey("Key3").Value = "Value3";
ini.AddSection("TEST_SECTION").AddKey("Key4").Value = "Value4";
ini.AddSection("TEST_SECTION").AddKey("Key5").Value = "Value5";
ini.AddSection("TEST_SECTION").AddKey("Key6").Value = "Value6";
ini.AddSection("TEST_SECTION").AddKey("Key7").Value = "Value7";
ini.AddSection("TEST_SECTION_2").AddKey("Key1").Value = "Value1";
ini.AddSection("TEST_SECTION_2").AddKey("Key2").Value = "Value2";
ini.AddSection("TEST_SECTION_2").AddKey("Key3").Value = "Value3";
ini.AddSection("TEST_SECTION_2").AddKey("Key4").Value = "Value4";
ini.AddSection("TEST_SECTION_2").AddKey("Key5").Value = "Value5";
ini.AddSection("TEST_SECTION_2").AddKey("Key6").Value = "Value6";
ini.AddSection("TEST_SECTION_2").AddKey("Key7").Value = "Value7";
// Key Rename Test
Trace.Write("Key Rename Key1 -> KeyTemp Test: ");
if (ini.RenameKey("TEST_SECTION", "Key1", "KeyTemp"))
Trace.WriteLine("Pass");
else
Trace.WriteLine("Fail");
// Section Rename Test
Trace.Write("Test section rename TEST_SECTION -> TEST_SECTION_3: ");
if (ini.RenameSection("TEST_SECTION", "TEST_SECTION_3"))
Trace.WriteLine("Pass");
else
Trace.WriteLine("Fail");
// Check Key Rename Post Section Rename
Trace.Write("Test TEST_SECTION_3 rename key KeyTemp -> Key1: ");
if (ini.RenameKey("TEST_SECTION_3", "KeyTemp", "Key1"))
Trace.WriteLine("Pass");
else
Trace.WriteLine("Fail");
// Check Section Rename Post Section Rename
Trace.Write("Test section rename TEST_SECTION_3 -> TEST_SECTION: ");
if (ini.RenameSection("TEST_SECTION_3", "TEST_SECTION"))
Trace.WriteLine("Pass");
else
Trace.WriteLine("Fail");
// Check Key Rename Key1 -> Key2 where Key2 exists
Trace.Write("Test TEST_SECTION key rename Key1 -> Key2 where Key2 exists: ");
if (ini.RenameKey("TEST_SECTION", "Key2", "Key1"))
Trace.WriteLine("Pass");
else
Trace.WriteLine("Fail");
// Check Key Rename
Trace.Write("Test TEST_SECTION key rename Key2 -> Key2Renamed: ");
if (ini.RenameKey("TEST_SECTION", "Key2", "Key2Renamed"))
Trace.WriteLine("Pass");
else
Trace.WriteLine("Fail");
// Test rename other section
Trace.Write("Test section rename TEST_SECTION_2 -> TEST_SECTION_1 : ");
if (ini.RenameSection("TEST_SECTION_2", "TEST_SECTION_1"))
Trace.WriteLine("Pass");
else
Trace.WriteLine("Fail");
// Check remove key
Trace.Write("Test TEST_SECTION_1 remove key Key1: ");
if (ini.GetSection("TEST_SECTION_1").RemoveKey("Key1"))
Trace.WriteLine("Pass");
else
Trace.WriteLine("Fail");
// Check remove key no exist
Trace.Write("Test TEST_SECTION_1 remove key Key1: ");
if (ini.GetSection("TEST_SECTION_1").RemoveKey("Key1"))
Trace.WriteLine("Pass");
else
Trace.WriteLine("Fail");
// Check remove section
Trace.Write("Test remove section TEST_SECTION_1: ");
if (ini.RemoveSection("TEST_SECTION_1"))
Trace.WriteLine("Pass");
else
Trace.WriteLine("Fail");
// Check remove section no exist
Trace.Write("Test remove section TEST_SECTION_1: ");
if (ini.RemoveSection("TEST_SECTION_1"))
Trace.WriteLine("Pass");
else
Trace.WriteLine("Fail");
//Save the INI
ini.Save("C:\\temp\\test.ini");
}
在 VB.NET 中使用 IniFile
此代码演示了在 VB.NET 中的用法
Sub Main()
Dim ini As New IniFile
' Load and existing file
' ini.Load("C:\temp\ini2open.ini")
ini.AddSection("TEST_SECTION").AddKey("Key1").Value = "Value1"
ini.AddSection("TEST_SECTION").AddKey("Key2").Value = "Value2"
ini.AddSection("TEST_SECTION").AddKey("Key3").Value = "Value3"
ini.AddSection("TEST_SECTION").AddKey("Key4").Value = "Value4"
ini.AddSection("TEST_SECTION").AddKey("Key5").Value = "Value5"
ini.AddSection("TEST_SECTION").AddKey("Key6").Value = "Value6"
ini.AddSection("TEST_SECTION").AddKey("Key7").Value = "Value7"
ini.AddSection("TEST_SECTION_2").AddKey("Key1").Value = "Value1"
ini.AddSection("TEST_SECTION_2").AddKey("Key2").Value = "Value2"
ini.AddSection("TEST_SECTION_2").AddKey("Key3").Value = "Value3"
ini.AddSection("TEST_SECTION_2").AddKey("Key4").Value = "Value4"
ini.AddSection("TEST_SECTION_2").AddKey("Key5").Value = "Value5"
ini.AddSection("TEST_SECTION_2").AddKey("Key6").Value = "Value6"
ini.AddSection("TEST_SECTION_2").AddKey("Key7").Value = "Value7"
' Key Rename Test
Trace.Write("Key Rename Key1 -> KeyTemp Test: ")
If ini.RenameKey("TEST_SECTION", "Key1", "KeyTemp") Then
Trace.WriteLine("Pass") Else Trace.WriteLine("Fail")
' Section Rename Test
Trace.Write("Test section rename TEST_SECTION -> TEST_SECTION_3: ")
If ini.RenameSection("TEST_SECTION", "TEST_SECTION_3") Then
Trace.WriteLine("Pass") Else Trace.WriteLine("Fail")
' Check Key Rename Post Section Rename
Trace.Write("Test TEST_SECTION_3 rename key KeyTemp -> Key1: ")
If ini.RenameKey("TEST_SECTION_3", "KeyTemp", "Key1") Then
Trace.WriteLine("Pass") Else Trace.WriteLine("Fail")
' Check Section Rename Post Section Rename
Trace.Write("Test section rename TEST_SECTION_3 -> TEST_SECTION: ")
If ini.RenameSection("TEST_SECTION_3", "TEST_SECTION") Then
Trace.WriteLine("Pass") Else Trace.WriteLine("Fail")
' Check Key Rename Key1 -> Key2 where Key2 exists
Trace.Write("Test TEST_SECTION key rename Key1 -> Key2 where Key2 exists: ")
If ini.RenameKey("TEST_SECTION", "Key2", "Key1") Then
Trace.WriteLine("Pass") Else Trace.WriteLine("Fail")
' Check Key Rename
Trace.Write("Test TEST_SECTION key rename Key2 -> Key2Renamed: ")
If ini.RenameKey("TEST_SECTION", "Key2", "Key2Renamed") Then
Trace.WriteLine("Pass") Else Trace.WriteLine("Fail")
' Test rename other section
Trace.Write("Test section rename TEST_SECTION_2 -> TEST_SECTION_1 : ")
If ini.RenameSection("TEST_SECTION_2", "TEST_SECTION_1") Then
Trace.WriteLine("Pass") Else Trace.WriteLine("Fail")
' Check remove key
Trace.Write("Test TEST_SECTION_1 remove key Key1: ")
If ini.GetSection("TEST_SECTION_1").RemoveKey("Key1") Then
Trace.WriteLine("Pass") Else Trace.WriteLine("Fail")
' Check remove key no exist
Trace.Write("Test TEST_SECTION_1 remove key Key1: ")
If ini.GetSection("TEST_SECTION_1").RemoveKey("Key1") Then
Trace.WriteLine("Pass") Else Trace.WriteLine("Fail")
' Check remove section
Trace.Write("Test remove section TEST_SECTION_1: ")
If ini.RemoveSection("TEST_SECTION_1") Then
Trace.WriteLine("Pass") Else Trace.WriteLine("Fail")
' Check remove section no exist
Trace.Write("Test remove section TEST_SECTION_1: ")
If ini.RemoveSection("TEST_SECTION_1") Then
Trace.WriteLine("Pass") Else Trace.WriteLine("Fail")
'Save the INI
ini.Save("C:\temp\test.ini")
End Sub
在 VBScript 中使用 IniFile
此代码演示了在 VBScript 中的用法
Option Explicit
Call Main
Sub Main()
Dim ini
Set ini = New IniFile
' Load and existing file
'ini.Load("C:\temp\ini2open.ini", false)
ini.AddSection("TEST_SECTION").AddKey("Key1").Value = "Value1"
ini.AddSection("TEST_SECTION").AddKey("Key2").Value = "Value2"
ini.AddSection("TEST_SECTION").AddKey("Key3").Value = "Value3"
ini.AddSection("TEST_SECTION").AddKey("Key4").Value = "Value4"
ini.AddSection("TEST_SECTION").AddKey("Key5").Value = "Value5"
ini.AddSection("TEST_SECTION").AddKey("Key6").Value = "Value6"
ini.AddSection("TEST_SECTION").AddKey("Key7").Value = "Value7"
ini.AddSection("TEST_SECTION_2").AddKey("Key1").Value = "Value1"
ini.AddSection("TEST_SECTION_2").AddKey("Key2").Value = "Value2"
ini.AddSection("TEST_SECTION_2").AddKey("Key3").Value = "Value3"
ini.AddSection("TEST_SECTION_2").AddKey("Key4").Value = "Value4"
ini.AddSection("TEST_SECTION_2").AddKey("Key5").Value = "Value5"
ini.AddSection("TEST_SECTION_2").AddKey("Key6").Value = "Value6"
ini.AddSection("TEST_SECTION_2").AddKey("Key7").Value = "Value7"
' Key Rename Test
If ini.RenameKey("TEST_SECTION","Key1","KeyTemp") Then
WScript.Echo "Pass" Else WScript.Echo "Fail"
' Section Rename Test
If ini.RenameSection("TEST_SECTION","TEST_SECTION_3") Then
WScript.Echo "Pass" Else WScript.Echo "Fail"
' Check Key Rename Post Section Rename
If ini.RenameKey("TEST_SECTION_3","KeyTemp","Key1") Then
WScript.Echo "Pass" Else WScript.Echo "Fail"
' Check Section Rename Post Section Rename
If ini.RenameSection("TEST_SECTION_3","TEST_SECTION") Then
WScript.Echo "Pass" Else WScript.Echo "Fail"
' Check Fail on Conflict
If ini.RenameKey("TEST_SECTION","Key2","Key1") Then
WScript.Echo "Pass" Else WScript.Echo "Fail"
' Check Fail on Conflict
If ini.RenameKey("TEST_SECTION","Key2","Key2Renamed") Then
WScript.Echo "Pass" Else WScript.Echo "Fail"
' Test rename other section
If ini.RenameSection("TEST_SECTION_2","TEST_SECTION_1") Then
WScript.Echo "Pass" Else WScript.Echo "Fail"
' Check remove key and conflict
If ini.GetSection("TEST_SECTION_1").RemoveKey("Key1") Then
WScript.Echo "Pass" Else WScript.Echo "Fail"
If ini.GetSection("TEST_SECTION_1").RemoveKey("Key1") Then
WScript.Echo "Pass" Else WScript.Echo "Fail"
' Check remove section and conflict
If ini.RemoveSection("TEST_SECTION_1") Then
WScript.Echo "Pass" Else WScript.Echo "Fail"
If ini.RemoveSection("TEST_SECTION_1") Then
WScript.Echo "Pass" Else WScript.Echo "Fail"
'Save the INI
ini.Save("C:\temp\test.ini")
End Sub
在 .NET 中使用该库
为了使用 IniFile
库,必须添加对 IniFile.dll 的引用。
历史
- 2007 年 12 月 14 日 - 创建 - 初始 VBScript 版本
- 2007 年 12 月 8 日 - 修复 Bug - Regex 解析字符串问题
- 2010 年 8 月 23 日 - 创建 - 使用哈希的 C# 版本
- 2010 年 8 月 23 日 - 创建 - 使用哈希的 VB.NET 版本
- 2010 年 8 月 23 日 - 创建 - 使用哈希的 VBScript 版本
- 2010 年 11 月 12 日 - 修复 Bug - 节的 Regex 匹配包含括号的键值
- 2015 年 6 月 20 日 - 修复 Bug - 键解析 Regex 以处理名称中带空格的键
- 2015 年 11 月 13 日 - 修复 Bug - 键解析 Regex 以处理包含多个等号的键
- 2021 年 5 月 6 日 - 修复 Bug - 节 Regex 以读取括号内的所有内容并进行修剪(单字符问题)