go-ini配置库

开发初衷

  • 需要一个支撑读写注释的INI工具包
  • 前身是goconfig,接口方法模仿了Windows API
    func (c *ConfigFile)GetValue(section, key string)(string, error)
  • 但有一些不足
    • 对配置文件的内容规范比较严格,支持不够广泛
    • 加载文件不支持附加选项,灵活性低
    • 是学Go早期的产物,内部实现一团乱麻
    • 当时没有版本的概念,改用gopkg.in路径另起炉灶

在线演示

  • GitHub 仓库:github.com/go-ini/ini
  • 演示内容:
    • 加载一个配置文件,并获取其中的内容
    • 直接映射配置到一个结构体上
    • 对配置做一些修改,然后保存到另一个文件

加载一个配置文件,并获取其中的内容

main.go与conf.ini位于同一级目录下

main.go

package main

import (
    "fmt"
    "gopkg.in/ini.v1"
    "log"
)

func main() {
    cfg, err := ini.Load("conf.ini")
    if err != nil {
        log.Fatal("Failed to load:", err)
    }
    port := cfg.Section("server").Key("http_port").String()
    fmt.Println("port:", port)
}

conf.ini

[server]
http_port = 3000

运行结构:
port: 3000

对配置做一些修改,然后保存到另一个文件

main.go

package main

import (
    "fmt"
    "gopkg.in/ini.v1"
    "log"
)

func main() {
    cfg, err := ini.Load("conf.ini")
    if err != nil {
        log.Fatal("Failed to load:", err)
    }
    port := cfg.Section("server").Key("http_port").String()
    //Section() 获取对应的分区
    fmt.Println("port:", port)

    cfg.Section("server").Key("http_port").SetValue("3001")
    err = cfg.SaveTo("conf2.ini")
    if err != nil {
        log.Fatal("Failed to save:", err)
    }
}

conf2.ini

[server]
http_port = 3001

目录结构:

配置文件直接映射配置到一个结构体上

package main

import (
    "fmt"
    "gopkg.in/ini.v1"
    "log"
)

type Server struct {
    HttpPort int
}

func main() {
    cfg, err := ini.Load("conf.ini")
    if err != nil {
        log.Fatal("Failed to load:", err)
    }
    //HttpPort在conf.ini未有对应的字段 需要进行映射
    cfg.NameMapper = ini.TitleUnderscore //下文会提供视频地址   视频内关于源码的介绍

    var s Server
    err = cfg.Section("server").MapTo(&s)
    if err != nil {
        log.Fatal("Failed to map:", err)
    }
    fmt.Println("server:", s)
}

运行结果:
未加cfg.NameMapper = ini.TitleUnderscore的情况下结果为:·· server: {0}
添加cfg.NameMapper = ini.TitleUnderscore的情况下结果为:·· server: {3000}

与市面上其他库的比较

  • INI相关库的横向比较中,其他库的功能过于基础,完全无法与之抗衡…
  • Viper:
    • :+1:支撑更丰富的配置格式,不仅限于INI,还支持JSON,YAML等等。
    • :+1:支撑监控配置变更
    • :+1:支撑对环境变量的自动绑定
    • :thumbsdown:不支持配置内容到结构体的双向映射(无法具体到GO类型)
    • :thumbsdown:不支持INI特有的相关用法

有哪些特点和不足

  • 特点:
    • 支持用多种方法混合加载配置:[]byte,文件或者io.ReadCloser
    • 支持注释读写操作
    • 支持各种INI的流派:MySQLGitPythonAWS 等等
    • Go量身定制的结构体双向映射
    • 自定义加载策略、数据验证、键名映射
  • 不足:
    • 不支持配置监控
    • 不支持Marshaller接口
    • 不支持重名分区
    • 不支持从网络地址加载
    • 仅支持UTF-8编码

设计思路

  • 不采用传统的AST解析方法
    • 鉴于INI的语法相对简单,使用按行解析更为直观
  • 凡是可直接对应到某个具体Go类型的,均提供便利方法一步到位
  • 在确保没有数据竞争的情况下,读性能要非常高
    • 用于i18n工具包的底层存储方案,每次渲染可能有上百次读操作
  • 尊重配置文件的原始格式
    • 保持文件时,若没有改动则要求输出一样的内容(空白符号除外)

性能一览

在进行基准测试的时候,如果加上数据静态检查,这个基准测试是不太准的,会慢上20倍左右。

源码速读

  • 如何提升读性能:BlockMode(Key).String vs (Key).Value
  • 如何支持多种数据源:LoadSources
  • 如何解析内容:(*File).parse
  • 如何支持键名映射:NameMapper
  • 如何支持结构体映射:(Section).MapTo、 (Section).ReflectForm

文章结尾视频链接 27:00-43:30

后续功能展望

  • 支持配置监控
    • 简化调用逻辑、内部确保线程安全
  • 支持从网络地址加载
    • 更好地配合应用集群拉取配置
  • 支持Marshaller接口(v2)
    • 允许用户自定义映射逻辑和错误处理

其他

平时的学习方法-Tip:找一个需要的东西去做,然后你会遇到很多问题,然后你就去查找解决这一些列问题,一开始你可能会觉得是针对某一个特定的问题,但你完成了几个小项目之后,这些都是你积累下的经验,这些经验是可以融会贯通的,然后你去看书,在你看书的过程中就能过联想到大概会是一个怎样的运用场景,然后结合书中的实例,发现原来还可以这样用。
推荐读物:有开发几个小项目的经验之后阅读效果更好

  • go并发编程——作为工具书查阅
  • go语言圣经
  • go语言实战

视频链接:#71 go-ini 配置库评析 by 无闻(unknwon)【 Go 夜读 】

相关文档:

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!