VB.NET 操作 INI 文件类

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")

六、注意事项与最佳实践

  1. 路径问题:如果未指定完整路径,INI 文件通常会位于 Windows 目录下。
  2. 缓冲区大小:读取大量数据时,适当增加缓冲区大小可以提高性能,但最大不超过 32767。
  3. 编码问题:INI 文件通常使用 ANSI 编码(代码页1252),如果需要支持 Unicode,需要考虑使用其他方法。
  4. 错误处理:在实际应用中,应该添加适当的错误处理机制。
  5. 性能考虑:频繁读写 INI 文件可能影响性能,可以考虑缓存机制。

七、扩展功能建议

  1. 添加缓存机制:将读取的数据缓存到内存中,减少文件 I/O 操作。
  2. 支持类型转换:添加对整数、布尔值等数据类型的自动转换支持。
  3. 添加事件通知:当 INI 文件被修改时,触发相应的事件。
  4. 支持注释:添加对 INI 文件中注释的读取和保留功能。
  5. 线程安全:如果需要在多线程环境中使用,添加线程安全机制。

单词、短语表

单词(短语) 音标 词性 词根/词缀 释义 搭配 例子
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 文件操作功能,可以根据实际需求进行扩展和优化。

相关推荐
API开发2 天前
apiSQL网关 for Docker 离线安装和升级教程
运维·docker·容器·api·api网关·apisql·替代graphql
新诺韦尔API3 天前
手机三要素验证接口详细技术对接指南
大数据·智能手机·api
没有bug.的程序员3 天前
Spring Boot 与 Swagger:API 文档自动化生成、版本管理与云原生协作深度实战指南
spring boot·云原生·自动化·api·swagger·版本管理·自动化生产
H Journey4 天前
yaml配置文件使用规则
配置文件·yaml
Li emily5 天前
如何通过外汇API平台快速实现实时数据接入?
开发语言·python·api·fastapi·美股
Onelafite7 天前
京东商品属性的详细api数据解析:颜色、尺寸与材质
linux·数据库·api·材质·开放api
nangonghen7 天前
centos 7.9安装postman v9.31.0
centos·api·postman
新诺韦尔API7 天前
手机三要素验证接口接入常见问题一览
大数据·智能手机·api
霑潇雨8 天前
Flink的转换算子——map
大数据·开发语言·flink·api
萧曵 丶8 天前
前端工程化项目中全类型配置文件的详细解析
前端·javascript·配置文件·工程化