INI 文件是一种经典的配置文件格式,广泛应用于 Windows 系统中。尽管现在更多应用转向 XML、JSON 或注册表等配置方式,INI 文件因其简单易读、易于手工修改的特点,仍在很多场景下被使用。本文将详细介绍如何在 VB.NET 中通过封装 Windows API 函数来读写 INI 文件,并提供一个功能完善的类实例。
一、INI 文件结构简介
INI 文件是一种简单的文本文件,其基本结构由节(Section)、键(Key)和值(Value)组成。例如:
ini
[Database]
Server=localhost
Port=3306
Username=admin
[Settings]
AutoStart=true
Theme=Dark
二、VB.NET 操作 INI 文件的实现原理
在 VB.NET 中,操作 INI 文件主要通过调用 Windows API 中的 kernel32.dll 提供的函数来实现。这些函数包括:
WritePrivateProfileString:写入字符串值GetPrivateProfileString:读取字符串值WritePrivateProfileStruct:写入结构体数据GetPrivateProfileStruct:读取结构体数据
三、完整的 VB.NET INI 操作类详解
下面是一个完整的 VB.NET 类,封装了对 INI 文件的各种操作,并添加了详细的中文注释:
vbnet
Imports System
Imports System.Text
Imports System.Runtime.InteropServices
Namespace Lob_ini
''' <summary>
''' INI 文件操作类
''' </summary>
Public Class cIni
' 定义 INI 文件路径
Private ls_IniFilename As String
' 定义读取缓冲区长度,默认256字节
Private li_BufferLen As Integer = 256
''' <summary>
''' 构造函数,初始化 INI 文件路径
''' </summary>
''' <param name="pIniFilename">INI 文件完整路径</param>
Public Sub New(ByVal pIniFilename As String)
MyBase.New()
ls_IniFilename = pIniFilename
End Sub
''' <summary>
''' INI 文件路径属性
''' </summary>
Public Property IniFile() As String
Get
Return ls_IniFilename
End Get
Set(ByVal value As String)
ls_IniFilename = value
End Set
End Property
''' <summary>
''' 缓冲区长度属性(最大值32767)
''' </summary>
Public Property BufferLen() As Integer
Get
Return li_BufferLen
End Get
Set(ByVal value As Integer)
' 限制缓冲区长度在合理范围内
If (value > 32767) Then
li_BufferLen = 32767
ElseIf (value < 1) Then
li_BufferLen = 1
Else
li_BufferLen = value
End If
End Set
End Property
' 声明 Windows API 函数 - 写入字符串到 INI 文件
Private Declare Function WritePrivateProfileString Lib "kernel32" (
ByVal pSection As String,
ByVal pKey As String,
ByVal pValue As String,
ByVal pFile As String) As Integer
' 声明 Windows API 函数 - 写入结构体到 INI 文件
Private Declare Function WritePrivateProfileStruct Lib "kernel32" (
ByVal pSection As String,
ByVal pKey As String,
ByVal pValue As String,
ByVal pValueLen As Integer,
ByVal pFile As String) As Integer
' 声明 Windows API 函数 - 从 INI 文件读取字符串
Private Declare Function GetPrivateProfileString Lib "kernel32" (
ByVal pSection As String,
ByVal pKey As String,
ByVal pDefault As String,
ByVal prReturn() As Byte,
ByVal pBufferLen As Integer,
ByVal pFile As String) As Integer
' 声明 Windows API 函数 - 从 INI 文件读取结构体
Private Declare Function GetPrivateProfileStruct Lib "kernel32" (
ByVal pSection As String,
ByVal pKey As String,
ByVal prReturn() As Byte,
ByVal pBufferLen As Integer,
ByVal pFile As String) As Integer
''' <summary>
''' 从 INI 文件读取指定键的值
''' </summary>
''' <param name="pSection">节名称</param>
''' <param name="pKey">键名称</param>
''' <param name="pDefault">默认值</param>
''' <returns>读取到的值或默认值</returns>
Public Overloads Function ReadValue(
ByVal pSection As String,
ByVal pKey As String,
ByVal pDefault As String) As String
Return z_GetString(pSection, pKey, pDefault)
End Function
''' <summary>
''' 从 INI 文件读取指定键的值(默认值为空字符串)
''' </summary>
''' <param name="pSection">节名称</param>
''' <param name="pKey">键名称</param>
''' <returns>读取到的值或空字符串</returns>
Public Overloads Function ReadValue(
ByVal pSection As String,
ByVal pKey As String) As String
Return z_GetString(pSection, pKey, "")
End Function
''' <summary>
''' 向 INI 文件写入键值对
''' </summary>
''' <param name="pSection">节名称</param>
''' <param name="pKey">键名称</param>
''' <param name="pValue">要写入的值</param>
Public Sub WriteValue(
ByVal pSection As String,
ByVal pKey As String,
ByVal pValue As String)
WritePrivateProfileString(pSection, pKey, pValue, Me.ls_IniFilename)
End Sub
''' <summary>
''' 从 INI 文件删除指定键
''' </summary>
''' <param name="pSection">节名称</param>
''' <param name="pKey">键名称</param>
Public Sub RemoveValue(
ByVal pSection As String,
ByVal pKey As String)
WritePrivateProfileString(pSection, pKey, Nothing, Me.ls_IniFilename)
End Sub
''' <summary>
''' 读取指定节中的所有键值对
''' </summary>
''' <param name="pSection">节名称</param>
''' <param name="pValues">返回的键值对数组</param>
Public Sub ReadValues(
ByVal pSection As String,
ByRef pValues As Array)
pValues = z_GetString(pSection, Nothing, Nothing).Split(CType(ChrW(0), Char))
End Sub
''' <summary>
''' 读取 INI 文件中的所有节名称
''' </summary>
''' <param name="pSections">返回的节名称数组</param>
Public Sub ReadSections(ByRef pSections As Array)
pSections = z_GetString(Nothing, Nothing, Nothing).Split(CType(ChrW(0), Char))
End Sub
''' <summary>
''' 从 INI 文件中删除整个节
''' </summary>
''' <param name="pSection">要删除的节名称</param>
Public Sub RemoveSection(ByVal pSection As String)
WritePrivateProfileString(pSection, Nothing, Nothing, Me.ls_IniFilename)
End Sub
''' <summary>
''' 内部方法:调用 GetPrivateProfileString API 读取数据
''' </summary>
Private Function z_GetString(
ByVal pSection As String,
ByVal pKey As String,
ByVal pDefault As String) As String
Dim sRet As String = pDefault
' 创建字节数组作为缓冲区
Dim bRet() As Byte = New Byte((li_BufferLen) - 1) {}
' 调用 API 读取数据
Dim i As Integer = GetPrivateProfileString(
pSection, pKey, pDefault, bRet, li_BufferLen, ls_IniFilename)
' 将字节数组转换为字符串并去除末尾的空字符
sRet = System.Text.Encoding.GetEncoding(1252).GetString(bRet, 0, i).TrimEnd(CType(ChrW(0), Char))
Return sRet
End Function
End Class
End Namespace
四、类关系图
下面是 cIni 类的 UML 类图,展示了其主要属性和方法:
cIni -String ls_IniFilename -Integer li_BufferLen +Property IniFile: String +Property BufferLen: Integer +New(pIniFilename: String) +ReadValue(pSection: String, pKey: String, pDefault: String) : String +ReadValue(pSection: String, pKey: String) : String +WriteValue(pSection: String, pKey: String, pValue: String) +RemoveValue(pSection: String, pKey: String) +ReadValues(pSection: String, ByRef pValues: Array) +ReadSections(ByRef pSections: Array) +RemoveSection(pSection: String) -z_GetString(pSection: String, pKey: String, pDefault: String) : String
五、使用示例
下面是如何使用上述 cIni 类来操作 INI 文件的示例:
vb
' 创建 cIni 实例,指定 INI 文件路径
Dim iniFile As New cIni("C:\config.ini")
' 写入配置值
iniFile.WriteValue("Database", "Server", "localhost")
iniFile.WriteValue("Database", "Port", "3306")
' 读取配置值
Dim server As String = iniFile.ReadValue("Database", "Server", "default_server")
Dim port As Integer = CInt(iniFile.ReadValue("Database", "Port", "1433"))
' 读取整个节的所有键
Dim values As Array = Nothing
iniFile.ReadValues("Database", values)
' 删除某个键
iniFile.RemoveValue("Database", "Port")
' 删除整个节
iniFile.RemoveSection("Database")
六、注意事项与最佳实践
- 路径问题:如果未指定完整路径,INI 文件通常会位于 Windows 目录下。
- 缓冲区大小:读取大量数据时,适当增加缓冲区大小可以提高性能,但最大不超过 32767。
- 编码问题:INI 文件通常使用 ANSI 编码(代码页1252),如果需要支持 Unicode,需要考虑使用其他方法。
- 错误处理:在实际应用中,应该添加适当的错误处理机制。
- 性能考虑:频繁读写 INI 文件可能影响性能,可以考虑缓存机制。
七、扩展功能建议
- 添加缓存机制:将读取的数据缓存到内存中,减少文件 I/O 操作。
- 支持类型转换:添加对整数、布尔值等数据类型的自动转换支持。
- 添加事件通知:当 INI 文件被修改时,触发相应的事件。
- 支持注释:添加对 INI 文件中注释的读取和保留功能。
- 线程安全:如果需要在多线程环境中使用,添加线程安全机制。
单词、短语表
| 单词(短语) | 音标 | 词性 | 词根/词缀 | 释义 | 搭配 | 例子 |
|---|---|---|---|---|---|---|
| Constructor | [kənˈstrʌktə] | n. | con-(共同)+ struct(建造)+ -or(人/物) | 构造函数 | class constructor | The constructor initializes the object. |
| Property | [ˈprɒpəti] | n. | proper(自己的)+ -ty(名词后缀) | 属性 | object property | The Name property stores the object's name. |
| Buffer | [ˈbʌfə] | n. | - | 缓冲区 | buffer size, buffer overflow | Increase the buffer size for better performance. |
| Declare | [dɪˈkleə] | v. | de-(完全)+ clar(清楚)+ -e | 声明 | declare function, declare variable | You need to declare the API function first. |
| Overloads | [ˌəʊvəˈləʊdz] | v. | over-(超过)+ load(负载) | 重载 | method overloads | The method overloads provide different parameter options. |
| Encoding | [ɪnˈkəʊdɪŋ] | n. | en-(使)+ code(代码)+ -ing | 编码 | character encoding, encoding format | Use proper encoding for multilingual support. |
| TrimEnd | [trɪm end] | v. | trim(修剪)+ end(末端) | 修剪末尾 | trim end characters | TrimEnd removes trailing characters. |
| Kernel32 | [ˈkɜːnəl θɜːti tuː] | n. | - | Windows 内核库 | kernel32.dll | Kernel32 provides core Windows functionality. |
| Private | [ˈpraɪvɪt] | adj. | priv(私有)+ -ate | 私有的 | private method, private variable | Private members are accessible only within the class. |
在 VB.NET 项目中有效地使用 INI 文件进行配置管理。这个类封装了基本的 INI 文件操作功能,可以根据实际需求进行扩展和优化。