一、viper簡介
viper 配置管理解析庫,是由大神 Steve Francia 開發,他在google領導著 golang 的產品開發,他也是 gohugo.io 的創始人之一,命令行解析庫 cobra 開發者。總之,他在golang領域是專家,很牛的一個人。
他的github地址:https://github.com/spf13
viper是一個配置管理的解決方案,它能夠從 json,toml,ini,yaml,hcl,env 等多種格式文件中,讀取配置內容,它還能從一些遠程配置中心讀取配置文件,如consul,etcd等;它還能夠監聽文件的內容變化。
viper的 logo:
二、viper功能介紹
- 讀取 json,toml,ini,yaml,hcl,env 等格式的文件內容
- 讀取遠程配置文件,如 consul,etcd 等和監控配置文件變化
- 讀取命令行 flag 的值
- 從 buffer 中讀取值
配置文件又可以分為不同的環境,比如dev,test,prod等。
viper 可以幫助你專注配置文件管理。
viper 讀取配置文件的優先順序,從高到低,如下:
- 顯式設置的Set函數
- 命令行參數
- 環境變量
- 配置文件
- 遠程k-v 存儲系統,如consul,etcd等
- 默認值
Viper 配置key是不區分大小寫的。
其實,上面的每一種文件格式,都有一些比較有名的解析庫,如:
- toml :https://github.com/BurntSushi/toml
- json :json的解析庫比較多,下面列出幾個常用的
https://github.com/json-iterator/go
https://github.com/mailru/easyjson
https://github.com/bitly/go-simplejson
https://github.com/tidwall/gjson
ini : https://github.com/go-ini/ini
等等單獨文件格式解析庫。
但是為啥子要用viper,因為它是一個綜合文件解析庫,包含了上面所有的文件格式解析,是一個集合體,少了配置多個庫的煩惱。
三、viper使用
安裝viper命令:
1
|
go get github.com/spf13/viper |
文檔: https://github.com/spf13/viper/blob/master/README.md#putting-values-into-viper
通過viper.Set設置值
如果某個鍵通過viper.Set設置了值,那么這個值讀取的優先級最高
1
|
viper.Set( "mysql.info" , "this is mysql info" ) |
設置默認值
https://github.com/spf13/viper/blob/master/README.md#establishing-defaults
viper 支持默認值的設置。如果配置文件、環境變量、遠程配置中沒有設置鍵值,就可以通過viper設置一些默認值。
Examples:
1
2
3
|
viper.SetDefault("ContentDir", "content") viper.SetDefault("LayoutDir", "layouts") viper.SetDefault("Taxonomies", map[string]string{"tag": "tags", "category": "categories"}) |
讀取配置文件
https://github.com/spf13/viper/blob/master/README.md#reading-config-files
讀取配置文件說明
讀取配置文件要求:最少要知道從哪個位置查找配置文件。用戶一定要設置這個路徑。
viper可以從多個路徑搜索配置文件,單個viper實例只支持單個配置文件。
viper本身沒有設置默認的搜索路徑,需要用戶自己設置默認路徑。
viper搜索和讀取配置文件例子片段:
1
2
3
4
5
6
7
8
9
|
viper.SetConfigName("config") // 配置文件的文件名,沒有擴展名,如 .yaml, .toml 這樣的擴展名 viper.SetConfigType("yaml") // 設置擴展名。在這里設置文件的擴展名。另外,如果配置文件的名稱沒有擴展名,則需要配置這個選項 viper.AddConfigPath("/etc/appname/") // 查找配置文件所在路徑 viper.AddConfigPath("$HOME/.appname") // 多次調用AddConfigPath,可以添加多個搜索路徑 viper.AddConfigPath(".") // 還可以在工作目錄中搜索配置文件 err := viper.ReadInConfig() // 搜索并讀取配置文件 if err != nil { // 處理錯誤 panic(fmt.Errorf("Fatal error config file: %s \n", err)) } |
說明:
這里執行viper.ReadInConfig()之后,viper才能確定到底用哪個文件,viper按照上面的AddConfigPath() 進行搜索,找到第一個名為 config.ext (這里的ext代表擴展名: 如 json,toml,yaml,yml,ini,prop 等擴展名) 的文件后即停止搜索。
如果有多個名稱為config的配置文件,viper怎么搜索呢?它會按照如下順序搜索
- config.json
- config.toml
- config.yaml
- config.yml
- config.properties (這種一般是java中的配置文件名)
- config.props (這種一般是java中的配置文件名)
你還可以處理一些特殊情況:
1
2
3
4
5
6
7
8
9
|
if err := viper.ReadInConfig(); err != nil { if _, ok := err.(viper.ConfigFileNotFoundError); ok { // 配置文件沒有找到; 如果需要可以忽略 } else { // 查找到了配置文件但是產生了其它的錯誤 } } // 查找到配置文件并解析成功 |
注意[自1.6起]: 你也可以有不帶擴展名的文件,并以編程方式指定其格式。對于位于用戶$HOME目錄中的配置文件沒有任何擴展名,如.bashrc。
例子1. 讀取配置文件
config.toml 配置文件:
1
2
3
4
5
6
7
8
9
10
|
# this is a toml title = "toml exaples" redis = "127.0.0.1:3300" # redis [mysql] host = "192.168.1.1" ports = 3306 username = "root" password = "root123456" |
viper_toml.go:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
package main import ( "fmt" "github.com/spf13/viper" ) // 讀取配置文件config type Config struct { Redis string MySQL MySQLConfig } type MySQLConfig struct { Port int Host string Username string Password string } func main() { // 把配置文件讀取到結構體上 var config Config viper.SetConfigName( "config" ) viper.AddConfigPath( "." ) err := viper.ReadInConfig() if err != nil { fmt.Println(err) return } viper.Unmarshal(&config) //將配置文件綁定到config上 fmt.Println( "config: " , config, "redis: " , config.Redis) } |
例子2. 讀取多個配置文件
在例子1基礎上多增加一個json的配置文件,config3.json 配置文件:
1
2
3
4
5
6
7
8
9
|
{ "redis": "127.0.0.1:33000", "mysql": { "port": 3306, "host": "127.0.0.1", "username": "root", "password": "123456" } } |
viper_multi.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
package main import ( "fmt" "github.com/spf13/viper" ) type Config struct { Redis string MySQL MySQLConfig } type MySQLConfig struct { Port int Host string Username string Password string } func main() { // 讀取 toml 配置文件 var config1 Config vtoml := viper.New() vtoml.SetConfigName( "config" ) vtoml.SetConfigType( "toml" ) vtoml.AddConfigPath( "." ) if err := vtoml.ReadInConfig(); err != nil { fmt.Println(err) return } vtoml.Unmarshal(&config1) fmt.Println( "read config.toml" ) fmt.Println( "config: " , config1, "redis: " , config1.Redis) // 讀取 json 配置文件 var config2 Config vjson := viper.New() vjson.SetConfigName( "config3" ) vjson.SetConfigType( "json" ) vjson.AddConfigPath( "." ) if err := vjson.ReadInConfig(); err != nil { fmt.Println(err) return } vjson.Unmarshal(&config2) fmt.Println( "read config3.json" ) fmt.Println( "config: " , config1, "redis: " , config1.Redis) } |
運行:
$ go run viper_multi.go
read config.toml
config: {127.0.0.1:33000 {0 192.168.1.1 root 123456}} redis: 127.0.0.1:33000
read config3.json
config: {127.0.0.1:33000 {0 192.168.1.1 root 123456}} redis: 127.0.0.1:33000
例子3. 讀取配置項的值
新建文件夾 item, 在里面創建文件 config.json,內容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
{ "redis": "127.0.0.1:33000", "mysql": { "port": 3306, "host": "127.0.0.1", "username": "root", "password": "123456", "ports": [ 5799, 6029 ], "metric": { "host": "127.0.0.1", "port": 2112 } } } |
item/viper_get_item.go 讀取配置項的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
package main import ( "fmt" "github.com/spf13/viper" ) func main() { viper.SetConfigName( "config" ) viper.SetConfigType( "json" ) viper.AddConfigPath( "." ) err := viper.ReadInConfig() //根據上面配置加載文件 if err != nil { fmt.Println(err) return } host := viper.Get( "mysql.host" ) username := viper.GetString( "mysql.username" ) port := viper.GetInt( "mysql.port" ) portsSlice := viper.GetIntSlice( "mysql.ports" ) metricPort := viper.GetInt( "mysql.metric.port" ) redis := viper.Get( "redis" ) mysqlMap := viper.GetStringMapString( "mysql" ) if viper.IsSet( "mysql.host" ) { fmt.Println( "[IsSet()]mysql.host is set" ) } else { fmt.Println( "[IsSet()]mysql.host is not set" ) } fmt.Println( "mysql - host: " , host, ", username: " , username, ", port: " , port) fmt.Println( "mysql ports :" , portsSlice) fmt.Println( "metric port: " , metricPort) fmt.Println( "redis - " , redis) fmt.Println( "mysqlmap - " , mysqlMap, ", username: " , mysqlMap[ "username" ]) } |
運行:
$ go run viper_get_item.go
[IsSet()]mysql.host is set
mysql - host: 127.0.0.1 , username: root , port: 3306
mysql ports : [5799 6029]
metric port: 2112
redis - 127.0.0.1:33000
mysqlmap - map[host:127.0.0.1 metric: password:123456 port:3306 ports: username:root] , username: root
如果把上面的文件config.json寫成toml格式,怎么解析? 改成config1.toml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# toml toml = "toml example" redis = "127.0.0.1:33000" [mysql] port = 3306 host = "127.0.0.1" username = "root" password = "123456" ports = [5799,6029] [mysql.metric] host = "127.0.0.1" port = 2112 |
其實解析代碼差不多,只需修改2處,
viper.SetConfigName("config") 里的 config 改成 config1 ,
viper.SetConfigType("json")里的 json 改成 toml,其余代碼都一樣。解析的效果也一樣。
viper獲取值的方法:
- Get(key string) : interface{}
- GetBool(key string) : bool
- GetFloat64(key string) : float64
- GetInt(key string) : int
- GetIntSlice(key string) : []int
- GetString(key string) : string
- GetStringMap(key string) : map[string]interface{}
- GetStringMapString(key string) : map[string]string
- GetStringSlice(key string) : []string
- GetTime(key string) : time.Time
- GetDuration(key string) : time.Duration
- IsSet(key string) : bool
- AllSettings() : map[string]interface{}
例子4. 讀取命令行的值
新建文件夾 cmd,然后cmd文件夾里新建config.json文件:
1
2
3
4
5
6
7
8
9
10
11
12
|
{ "redis":{ "port": 3301, "host": "127.0.0.1" }, "mysql": { "port": 3306, "host": "127.0.0.1", "username": "root", "password": "123456" } } |
go解析文件,cmd/viper_pflag.go:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
package main import ( "fmt" "github.com/spf13/pflag" "github.com/spf13/viper" ) func main() { pflag.Int( "redis.port" , 3302 , "redis port" ) viper.BindPFlags(pflag.CommandLine) pflag.Parse() viper.SetConfigName( "config" ) viper.SetConfigType( "json" ) viper.AddConfigPath( "." ) err := viper.ReadInConfig() //根據上面配置加載文件 if err != nil { fmt.Println(err) return } host := viper.Get( "mysql.host" ) username := viper.GetString( "mysql.username" ) port := viper.GetInt( "mysql.port" ) redisHost := viper.GetString( "redis.host" ) redisPort := viper.GetInt( "redis.port" ) fmt.Println( "mysql - host: " , host, ", username: " , username, ", port: " , port) fmt.Println( "redis - host: " , redisHost, ", port: " , redisPort) } |
1.不加命令行參數運行:
$ go run viper_pflag.go
mysql - host: 127.0.0.1 , username: root , port: 3306
redis - host: 127.0.0.1 , port: 3301
說明:redis.port 的值是 3301,是 config.json 配置文件里的值。
2.加命令行參數運行
$ go run viper_pflag.go --redis.port 6666
mysql - host: 127.0.0.1 , username: root , port: 3306
redis - host: 127.0.0.1 , port: 6666
說明:加了命令行參數 --redis.port 6666
,這時候redis.port輸出的值為 6666
,讀取的是cmd命令行的值
例子5:io.Reader中讀取值
https://github.com/spf13/viper#reading-config-from-ioreader
viper_ioreader.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
package main import ( "bytes" "fmt" "github.com/spf13/viper" ) func main() { viper.SetConfigType( "yaml" ) var yaml = [] byte (` Hacker: true name: steve hobbies: - skateboarding - snowboarding - go clothing: jacket: leather trousers: denim age: 35 eyes : brown beard: true `) err := viper.ReadConfig(bytes.NewBuffer(yaml)) if err != nil { fmt.Println(err) return } hacker := viper.GetBool( "Hacker" ) hobbies := viper.GetStringSlice( "hobbies" ) jacket := viper.Get( "clothing.jacket" ) age := viper.GetInt( "age" ) fmt.Println( "Hacker: " , hacker, ",hobbies: " , hobbies, ",jacket: " , jacket, ",age: " , age) } |
例子6:寫配置文件
https://github.com/spf13/viper#writing-config-files
新建文件 writer/viper_write_config.go:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
package main import ( "fmt" "github.com/spf13/viper" ) func main() { viper.SetConfigName( "config" ) viper.SetConfigType( "yaml" ) viper.AddConfigPath( "." ) viper.Set( "yaml" , "this is a example of yaml" ) viper.Set( "redis.port" , 4405 ) viper.Set( "redis.host" , "127.0.0.1" ) viper.Set( "mysql.port" , 3306 ) viper.Set( "mysql.host" , "192.168.1.0" ) viper.Set( "mysql.username" , "root123" ) viper.Set( "mysql.password" , "root123" ) if err := viper.WriteConfig(); err != nil { fmt.Println(err) } } |
運行:
$ go run viper_write_config.go
沒有任何輸出表示生成配置文件成功
1
2
3
4
5
6
7
8
9
|
mysql: host: 192.168 . 1.0 password: root123 port: 3306 username: root123 redis: host: 127.0 . 0.1 port: 4405 yaml: this is a example of yaml |
WriteConfig() 和 SafeWriteConfig() 區別:
如果待生成的文件已經存在,那么SafeWriteConfig()就會報錯,Config File "config.yaml" Already Exists
, 而WriteConfig()則會直接覆蓋同名文件。
四、參考
到此這篇關于golang常用庫之配置文件解析庫-viper使用詳解的文章就介紹到這了,更多相關golang配置文件解析庫viper內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!
原文鏈接:https://www.cnblogs.com/jiujuan/p/13799976.html