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
方法裡讀取。
另外關於配置熱更新,可以檢視這份文章:熱更新配置檔案