欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Go语言中INI配置文件格式解析

程序员文章站 2022-07-09 19:09:20
init配置文件与解析 INI配置文件有三要素 1. parameters 指一条配置,就像key = value这样的。 2. sections sections是parameters的集合,sections必须独占一行并且用[]括起来。 sections没有明显的结束方式,一个sections的 ......

init配置文件与解析

ini配置文件有三要素

  1. parameters

  指一条配置,就像key = value这样的。

  1. sections

  sections是parameters的集合,sections必须独占一行并且用[]括起来。

  sections没有明显的结束方式,一个sections的开始就是另一个sections的结束。

  1. comments

  指ini配置文件的注释,以 ; 开头。

[database]
serverip=**********
serverport=8080
controlconnectstring=qwdj7+xh6owaanaghvgh5/5uxyra2rfz/ufakdln1h9tw+v7z0socfr+wydyzcjf/anufpxlo6cldahm4xxmbadyks6zmkwugqngdzmpx6c=
controlconnectcategory=0
 
[logoninfo]
saveuserid=y
userid=admin
dbserver=appdb
dbcenter=demo
 
[userconfig]
opendownloadfileatonec=y
windowstyle=devexpress dark style
 
[language]
language=chs
 
[autoupdate]
version=1.1

init 配置文件的解析

这里我们使用github上的第三方库(https://github.com/go-ini)

Go语言中INI配置文件格式解析

**package ini provides ini file read and write functionality in go. **

安装

the minimum requirement of go is 1.6.

$ go get gopkg.in/ini.v1

please add -u flag to update in the future.

开始使用

我们将通过一个非常简单的例子来了解如何使用。

首先,我们需要在任意目录创建两个文件(my.inimain.go),在这里我们选择 /tmp/ini 目录。

$ mkdir -p /tmp/ini
$ cd /tmp/ini
$ touch my.ini main.go
$ tree .
.
├── main.go
└── my.ini

0 directories, 2 files

现在,我们编辑 my.ini 文件并输入以下内容(部分内容来自 grafana)。

# possible values : production, development
app_mode = development

[paths]
# path to where grafana can store temp files, sessions, and the sqlite3 db (if that is used)
data = /home/git/grafana

[server]
# protocol (http or https)
protocol = http

# the http port  to use
http_port = 9999

# redirect to correct domain if host header does not match domain
# prevents dns rebinding attacks
enforce_domain = true

很好,接下来我们需要编写 main.go 文件来操作刚才创建的配置文件。

package main

import (
    "fmt"
    "os"

    "gopkg.in/ini.v1"
)

func main() {
    cfg, err := ini.load("my.ini")//初始化一个cfg
    if err != nil {
        fmt.printf("fail to read file: %v", err)
        os.exit(1)
    }

    // 典型读取操作,默认分区可以使用空字符串表示
    fmt.println("app mode:", cfg.section("").key("app_mode").string())
    fmt.println("data path:", cfg.section("paths").key("data").string())

    // 我们可以做一些候选值限制的操作
    fmt.println("server protocol:",
        cfg.section("server").key("protocol").in("http", []string{"http", "https"}))
    // 如果读取的值不在候选列表内,则会回退使用提供的默认值
    fmt.println("email protocol:",
        cfg.section("server").key("protocol").in("smtp", []string{"imap", "smtp"}))

    // 试一试自动类型转换
    fmt.printf("port number: (%[1]t) %[1]d\n", cfg.section("server").key("http_port").mustint(9999))
    fmt.printf("enforce domain: (%[1]t) %[1]v\n", cfg.section("server").key("enforce_domain").mustbool(false))
    
    // 差不多了,修改某个值然后进行保存
    cfg.section("").key("app_mode").setvalue("production")
    cfg.saveto("my.ini.local")
}

运行程序,我们可以看下以下输出

$ go run main.go
app mode: development
data path: /home/git/grafana
server protocol: http
email protocol: smtp
port number: (int) 9999
enforce domain: (bool) true

$ cat my.ini.local
# possible values : production, development
app_mode = production

[paths]
# path to where grafana can store temp files, sessions, and the sqlite3 db (if that is used)
data = /home/git/grafana
...

高级用法

将配制文件映射到结构体

想要使用更加面向对象的方式玩转 ini 吗?好主意。

配置文件如下:

name = unknwon
age = 21
male = true
born = 1993-01-01t20:17:05z

[note]
content = hi is a good man!
cities = hangzhou, boston
//按照配置文件的内容构造结构体
type note struct {
    content string
    cities  []string
}

type person struct {
    name string
    age  int `ini:"age"`//这里需要用到反射,因为和ini文件的字段不同
    male bool
    born time.time
    note
    created time.time `ini:"-"`
}

func main() {
    cfg, err := ini.load("path/to/ini")
    // ...
    p := new(person)//初始化一个结构体,返回指向他的指针
    err = cfg.mapto(p)
    // ...

    // 一切竟可以如此的简单。
    err = ini.mapto(p, "path/to/ini")//核心代码
    // ...

    // 嗯哼?只需要映射一个分区吗?
    n := new(note)
    err = cfg.section("note").mapto(n)
    // ...
}

结构的字段怎么设置默认值呢?很简单,只要在映射之前对指定字段进行赋值就可以了。如果键未找到或者类型错误,该值不会发生改变。

// ...
p := &person{
    name: "joe",
}
// ..

将结构体映射成配置文件

type embeded struct {
    dates  []time.time `delim:"|" comment:"time data"`
    places []string    `ini:"places,omitempty"`
    none   []int       `ini:",omitempty"`
}

type author struct {
    name      string `ini:"name"`
    male      bool
    age       int `comment:"author's age"`
    gpa       float64
    nevermind string `ini:"-"`
    *embeded `comment:"embeded section"`
}

func main() {
    a := &author{"unknwon", true, 21, 2.8, "",
        &embeded{
            []time.time{time.now(), time.now()},
            []string{"hangzhou", "boston"},
            []int{},
        }}
    cfg := ini.empty()//初始化一个空配置文件
    err = ini.reflectfrom(cfg, a)//核心代码
    // ...
}

瞧瞧,奇迹发生了。

name = unknwon
male = true
; author's age
age = 21
gpa = 2.8

; embeded section
[embeded]
; time data
dates = 2015-08-07t22:14:22+08:00|2015-08-07t22:14:22+08:00
places = hangzhou,boston

参考文献: