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
方法里讀取。
另外關於配置熱更新,可以查看這份文章:熱更新配置文件