golang常⽤库之配置⽂件解析库-viper使⽤详解
⼀、viper简介
viper配置管理解析库,是由⼤神Steve Francia开发,他在google领导着golang的产品开发,他也是gohugo.io的创始⼈之⼀,命令⾏解析库cobra开发者。总之,他在golang领域是专家,很⽜的⼀个⼈。
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 :github/BurntSushi/toml
json :json的解析库⽐较多,下⾯列出⼏个常⽤的
但是为啥⼦要⽤viper,因为它是⼀个综合⽂件解析库,包含了上⾯所有的⽂件格式解析,是⼀个集合体,少了配置多个库的烦恼。
三、viper使⽤
安装viper命令:
go get github/spf13/viper
通过viper.Set设置值
如果某个键通过viper.Set设置了值,那么这个值读取的优先级最⾼
viper.Set("mysql.info", "this is mysql info")
设置默认值
viper ⽀持默认值的设置。如果配置⽂件、环境变量、远程配置中没有设置键值,就可以通过viper设置⼀些默认值。Examples:
viper.SetDefault("ContentDir", "content")
viper.SetDefault("LayoutDir", "layouts")
viper.SetDefault("Taxonomies", map[string]string{"tag": "tags", "category": "categories"})
读取配置⽂件
读取配置⽂件说明
读取配置⽂件要求:最少要知道从哪个位置查配置⽂件。⽤户⼀定要设置这个路径。
viper可以从多个路径搜索配置⽂件,单个viper实例只⽀持单个配置⽂件。
viper本⾝没有设置默认的搜索路径,需要⽤户⾃⼰设置默认路径。
viper搜索和读取配置⽂件例⼦⽚段:
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() 进⾏搜索,到第⼀个名为 (这⾥的ext代表扩展名:如 json,toml,yaml,yml,ini,prop 等扩展名) 的⽂件后即停⽌搜索。
如果有多个名称为config的配置⽂件,viper怎么搜索呢?它会按照如下顺序搜索
config.json
config.yaml
config.properties (这种⼀般是java中的配置⽂件名)
config.props (这种⼀般是java中的配置⽂件名)
你还可以处理⼀些特殊情况:
if err := viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
// 配置⽂件没有到; 如果需要可以忽略
} else {
// 查到了配置⽂件但是产⽣了其它的错误
}
}
// 查到配置⽂件并解析成功
注意[⾃1.6起]:你也可以有不带扩展名的⽂件,并以编程⽅式指定其格式。对于位于⽤户$HOME⽬录中的配置⽂件没有任何扩展名,如.bashrc。
例⼦1. 读取配置⽂件
# 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"
飞刀又见飞刀结局
:
package main
import(
"fmt"
"github/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 配置⽂件:{
"redis": "127.0.0.1:33000",
"mysql": {
"port": 3306,
"host": "127.0.0.1",
"username": "root",
"password": "123456"
}
}
package main
import (
"fmt"
"github/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("l")
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
l
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,内容如下:
{
"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_ 读取配置项的值
package main
import (
"fmt"
"github/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("ic.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_
[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格式,怎么解析?改成l:
# 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]
[ic]
host = "127.0.0.1"
port = 2112
其实解析代码差不多,只需修改2处,
viper.SetConfigName("config") ⾥的 config 改成 config1 ,
viper.SetConfigType("json")⾥的 json 改成 toml,其余代码都⼀样。解析的效果也⼀样。