go-ini入门教程
go-ini入门教程
go-ini简介
Package ini provides INI file read and write functionality in Go.
在实际开发时,配置信息一般不会在代码里硬编码,通常是放在配置文件里,或者数据库、缓存里。今天介绍的 go-ini
就是一个读写 ini
文件的库。
配置文件格式有很多,常用的有 json
、xml
、ini
。其中 ini
是以节(section)和键(key)构成,如下所示:
#debug or release
RUN_MODE = debug
[app]
PAGE_SIZE = 10
快速使用
1、下载安装
使用一个特定版本:
$ go get gopkg.in/ini.v1
使用最新版本:
$ go get github.com/go-ini/ini
如需更新请添加 -u
选项。
2、创建两个文件(my.ini
和 main.go
),这里选择放在 /home/ini-sample
目录。
$ mkdir -p /home/ini-sample
$ cd /home/ini-sample
$ touch my.ini main.go
$ tree .
.
├── main.go
└── my.ini
0 directories, 2 files
3、编译 my.ini
文件并输入以下内容:
#debug or release
RUN_MODE = debug
[app]
PAGE_SIZE = 10
[server]
HTTP_PORT = 8000
READ_TIMEOUT = 60
WRITE_TIMEOUT = 60
[database]
TYPE = mysql
USER = 数据库账号
PASSWORD = 数据库密码
#127.0.0.1:3306
HOST = 数据库IP:数据库端口号
NAME = blog
TABLE_PREFIX = blog_
4、接着编写 main.go
文件来操作刚才创建的配置文件。
package main
import (
"fmt"
"os"
"gopkg.in/ini.v1"
)
func main() {
cfg, err := ini.Load("my.ini")
if err != nil {
fmt.Printf("Fail to read file: %v", err)
os.Exit(1)
}
// 典型读取操作,默认分区可以使用空字符串表示
fmt.Println("Run Mode:", cfg.Section("").Key("RUN_MODE").String())
fmt.Println("Page Size:", cfg.Section("app").Key("PAGE_SIZE").String())
// 试一试自动类型转换
fmt.Printf("Http Port: (%[1]T) %[1]d\n", cfg.Section("server").Key("HTTP_PORT").MustInt(9999))
// 差不多了,修改某个值然后进行保存
cfg.Section("").Key("RUN_MODE").SetValue("release")
cfg.SaveTo("my.ini.local")
}
5、运行程序,可以看到以下输出:
$ go run main.go
Run Mode: debug
Page Size: 10
Http Port: (int) 8000
$ cat my.ini.local
# debug or release
RUN_MODE = release
[app]
PAGE_SIZE = 10
[server]
HTTP_PORT = 8000
READ_TIMEOUT = 60
WRITE_TIMEOUT = 60
[database]
TYPE = mysql
USER = 数据库账号
PASSWORD = 数据库密码
# 127.0.0.1:3306
HOST = 数据库IP:数据库端口号
NAME = blog
TABLE_PREFIX = blog_
操作分区(Section)
获取指定分区:
sec, err := cfg.GetSection("section name")
如果想要获取默认分区,则可以用空字符串代替分区名:
sec, err := cfg.GetSection("")
操作键值(Value)
获取一个类型为字符串(string)的值:
val := cfg.Section("").Key("key name").String()
Must*方法
当我们知道配置的键值是哪种格式时,可以使用 Must*
方法来获取。
v = cfg.Section("").Key("BOOL").MustBool()
v = cfg.Section("").Key("FLOAT64").MustFloat64()
v = cfg.Section("").Key("INT").MustInt()
v = cfg.Section("").Key("INT64").MustInt64()
v = cfg.Section("").Key("UINT").MustUint()
v = cfg.Section("").Key("UINT64").MustUint64()
v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339)
v = cfg.Section("").Key("TIME").MustTime() // RFC3339
// 由 Must 开头的方法名允许接收一个相同类型的参数来作为默认值,
// 当键不存在或者转换失败时,则会直接返回该默认值。
// 但是,MustString 方法必须传递一个默认值。
v = cfg.Section("").Key("String").MustString("default")
v = cfg.Section("").Key("BOOL").MustBool(true)
v = cfg.Section("").Key("FLOAT64").MustFloat64(1.25)
v = cfg.Section("").Key("INT").MustInt(10)
v = cfg.Section("").Key("INT64").MustInt64(99)
v = cfg.Section("").Key("UINT").MustUint(3)
v = cfg.Section("").Key("UINT64").MustUint64(6)
v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339, time.Now())
v = cfg.Section("").Key("TIME").MustTime(time.Now()) // RFC3339
In*方法
获取键值时设定候选值,可以使用 In*
方法:
v = cfg.Section("").Key("STRING").In("default", []string{"str", "arr", "types"})
v = cfg.Section("").Key("FLOAT64").InFloat64(1.1, []float64{1.25, 2.5, 3.75})
v = cfg.Section("").Key("INT").InInt(5, []int{10, 20, 30})
v = cfg.Section("").Key("INT64").InInt64(10, []int64{10, 20, 30})
v = cfg.Section("").Key("UINT").InUint(4, []int{3, 6, 9})
v = cfg.Section("").Key("UINT64").InUint64(8, []int64{3, 6, 9})
v = cfg.Section("").Key("TIME").InTimeFormat(time.RFC3339, time.Now(), []time.Time{time1, time2, time3})
v = cfg.Section("").Key("TIME").InTime(time.Now(), []time.Time{time1, time2, time3}) // RFC3339
如果获取到的值不是候选值的任意一个,则会返回默认值,而默认值不需要是候选值中的一员。
结构体与分区映射
有时候我们不想逐个获取值,而是把分区内的值放到一个结构体里,以便使用。
配置文件:
#debug or release
RUN_MODE = debug
[app]
PAGE_SIZE = 10
[server]
HTTP_PORT = 8000
READ_TIMEOUT = 60
WRITE_TIMEOUT = 60
[database]
TYPE = mysql
USER = 数据库账号
PASSWORD = 数据库密码
#127.0.0.1:3306
HOST = 数据库IP:数据库端口号
NAME = blog
TABLE_PREFIX = blog_
代码:
type Database struct {
Type string
User string
Password string
Host string
Name string
TablePrefix string
}
func Setup() {
Cfg, err := ini.Load("conf/app.ini")
if err != nil {
log.Fatalf("Fail to parse 'conf/app.ini': %v", err)
}
err = Cfg.Section("database").MapTo(DatabaseSetting)
if err != nil {
log.Fatalf("Cfg.MapTo DatabaseSetting err: %v", err)
}
}
使用心得
通常配置文件很少变更的,一般使用单例,在 go 里就是包内变量了,由于只需要读取一次,所以一般会在 init
方法里读取。
另外关于配置热更新,可以查看这份文章:热更新配置文件