

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
'''
''' INI 文件操作类
'''
Public Class cIni
' 定义 INI 文件路径
Private ls_IniFilename As String
' 定义读取缓冲区长度,默认256字节
Private li_BufferLen As Integer = 256
'''
''' 构造函数,初始化 INI 文件路径
'''
''' INI 文件完整路径
Public Sub New(ByVal pIniFilename As String)
MyBase.New()
ls_IniFilename = pIniFilename
End Sub
'''
''' INI 文件路径属性
'''
Public Property IniFile() As String
Get
Return ls_IniFilename
End Get
Set(ByVal value As String)
ls_IniFilename = value
End Set
End Property
'''
''' 缓冲区长度属性(最大值32767)
'''
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
'''
''' 从 INI 文件读取指定键的值
'''
''' 节名称
''' 键名称
''' 默认值
'''
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
'''
''' 从 INI 文件读取指定键的值(默认值为空字符串)
'''
''' 节名称
''' 键名称
'''
Public Overloads Function ReadValue(
ByVal pSection As String,
ByVal pKey As String) As String
Return z_GetString(pSection, pKey, "")
End Function
'''
''' 向 INI 文件写入键值对
'''
''' 节名称
''' 键名称
''' 要写入的值
Public Sub WriteValue(
ByVal pSection As String,
ByVal pKey As String,
ByVal pValue As String)
WritePrivateProfileString(pSection, pKey, pValue, Me.ls_IniFilename)
End Sub
'''
''' 从 INI 文件删除指定键
'''
''' 节名称
''' 键名称
Public Sub RemoveValue(
ByVal pSection As String,
ByVal pKey As String)
WritePrivateProfileString(pSection, pKey, Nothing, Me.ls_IniFilename)
End Sub
'''
''' 读取指定节中的所有键值对
'''
''' 节名称
''' 返回的键值对数组
Public Sub ReadValues(
ByVal pSection As String,
ByRef pValues As Array)
pValues = z_GetString(pSection, Nothing, Nothing).Split(CType(ChrW(0), Char))
End Sub
'''
''' 读取 INI 文件中的所有节名称
'''
''' 返回的节名称数组
Public Sub ReadSections(ByRef pSections As Array)
pSections = z_GetString(Nothing, Nothing, Nothing).Split(CType(ChrW(0), Char))
End Sub
'''
''' 从 INI 文件中删除整个节
'''
''' 要删除的节名称
Public Sub RemoveSection(ByVal pSection As String)
WritePrivateProfileString(pSection, Nothing, Nothing, Me.ls_IniFilename)
End Sub
'''
''' 内部方法:调用 GetPrivateProfileString API 读取数据
'''
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 文件操作功能,可以根据实际需求进行扩展和优化。

