Go语言配置解析库viper

news/2024/11/15 6:49:46/

Go语言配置解析库viper

1、viper简介

viper 配置管理解析库,是由大神 Steve Francia 开发,他在google领导着 golang 的产品开发,他也是 gohugo.io

的创始人之一,命令行解析库 cobra 开发者。

viper是一个配置管理的解决方案,它能够从 json,toml,ini,yaml,hcl,env 等多种格式文件中,读取配置内

容,它还能从一些远程配置中心读取配置文件,如consul,etcd等;它还能够监听文件的内容变化。

2、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,因为它是一个综合文件解析库,包含了上面所有的文件格式解析,是一个集合体,少了配

置多个库的烦恼。

3、viper使用

安装viper命令:

go get github.com/spf13/viper

文档:

https://github.com/spf13/viper/blob/master/README.md#putting-values-into-viper

3.1 通过viper.Set设置值

如果某个键通过viper.Set设置了值,那么这个值读取的优先级最高

viper.Set("mysql.info", "this is mysql info")

3.2 设置默认值

https://github.com/spf13/viper/blob/master/README.md#establishing-defaults

viper 支持默认值的设置。如果配置文件、环境变量、远程配置中没有设置键值,就可以通过viper设置一些默认

值。

viper.SetDefault("ContentDir", "content")
viper.SetDefault("LayoutDir", "layouts")
viper.SetDefault("Taxonomies", map[string]string{"tag": "tags", "category": "categories"})

3.3 读取配置文件

https://github.com/spf13/viper/blob/master/README.md#reading-config-files

读取配置文件要求:最少要知道从哪个位置查找配置文件。用户一定要设置这个路径。

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() 进行搜索,找到第一个名为 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中的配置文件名)

你还可以处理一些特殊情况:

if err := viper.ReadInConfig(); err != nil {if _, ok := err.(viper.ConfigFileNotFoundError); ok {        // 配置文件没有找到; 如果需要可以忽略} else {        // 查找到了配置文件但是产生了其它的错误}
}
// 查找到配置文件并解析成功

注意[自1.6起]: 你也可以有不带扩展名的文件,并以编程方式指定其格式。对于位于用户$HOME目录中的

配置文件没有任何扩展名,如.bashrc。

3.4 例子1:读取配置文件

config.toml 配置文件:

title = "toml exaples"
redis = "127.0.0.1:3300"
[mysql]
host = "192.168.1.1"
ports = 3306
username = "root"
password = "root123456"
package mainimport("fmt""github.com/spf13/viper"
)// 读取配置文件config
type Config struct {Redis stringMySQL MySQLConfig
}type MySQLConfig struct {Port intHost stringUsername stringPassword string
}func main() {// 把配置文件读取到结构体上var config Configviper.SetConfigName("config")viper.AddConfigPath(".")err := viper.ReadInConfig()if err != nil {fmt.Println(err)return}//将配置文件绑定到config上viper.Unmarshal(&config)fmt.Println("config: ", config, "redis: ", config.Redis)
}
# 输出
config:  {127.0.0.1:3300 {0 192.168.1.1 root root123456}} redis:  127.0.0.1:3300

3.5 例子2:读取多个配置文件

在例子1基础上多增加一个json的配置文件,config1.json 配置文件:

{"redis": "127.0.0.1:33000","mysql": {"port": 3306,"host": "127.0.0.1","username": "root","password": "123456"}
}

读取多个配置文件:

package mainimport ("fmt""github.com/spf13/viper"
)type Config struct {Redis stringMySQL MySQLConfig
}type MySQLConfig struct {Port     intHost     stringUsername stringPassword string
}func main() {// 读取 toml 配置文件var config1 Configvtoml := 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 Configvjson := viper.New()vjson.SetConfigName("config1")vjson.SetConfigType("json")vjson.AddConfigPath(".")if err := vjson.ReadInConfig(); err != nil {fmt.Println("bb",err)return}vjson.Unmarshal(&config2)fmt.Println("read config1.json")fmt.Println("config: ", config2, "redis: ", config2.Redis)
}

运行:

# 输出
read config.toml
config:  {127.0.0.1:3300 {0 192.168.1.1 root root123456}} redis:  127.0.0.1:3300read config1.json
config:  {127.0.0.1:33000 {3306 127.0.0.1 root 123456}} redis:  127.0.0.1:33000

3.6 例子3:读取配置项的值

新建文件夹 item, 在里面创建文件 config2.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}}
}

读取配置项的值:

package mainimport ("fmt""github.com/spf13/viper"
)func main() {viper.SetConfigName("config2")viper.SetConfigType("json")viper.AddConfigPath("item")// 根据上面配置加载文件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"])
}

运行:

# 输出
[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

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{}

3.7 例子4:读取命令行的值

新建文件夹 cmd,然后cmd文件夹里新建config.json文件:

{"redis":{"port": 3301,"host": "127.0.0.1"},"mysql": {"port": 3306,"host": "127.0.0.1","username": "root","password": "123456"}
}

读取命令行的值:

package mainimport ("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("config3")viper.SetConfigType("json")viper.AddConfigPath("cmd")// 根据上面配置加载文件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 004.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 004.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命令行的值。

3.8 例子5:io.Reader中读取值

https://github.com/spf13/viper#reading-config-from-ioreader

package mainimport ("bytes""fmt""github.com/spf13/viper"
)func main() {viper.SetConfigType("yaml")var yaml = []byte(`
Hacker: true
name: steve
hobbies:
- skateboarding
- snowboarding
- go
clothing:jacket: leathertrousers: 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)
}
# 输出
Hacker:  true ,hobbies:  [skateboarding snowboarding go] ,jacket:  leather ,age: 35

3.9 例子6:写配置文件

https://github.com/spf13/viper#writing-config-files

package mainimport ("fmt""github.com/spf13/viper"
)func main() {viper.SetConfigName("config4")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)}
}

没有任何输出表示生成配置文件成功:

mysql:host: 192.168.1.0password: root123port: 3306username: root123
redis:host: 127.0.0.1port: 4405
yaml: this is a example of yaml

WriteConfig() 和 SafeWriteConfig() 区别:

如果待生成的文件已经存在,那么SafeWriteConfig()就会报错:

Config File "config.yaml" Already Exists

而WriteConfig()则会直接覆盖同名文件。


http://www.ppmy.cn/news/246216.html

相关文章

CVE漏洞复现-CVE-2023-32233 NetFilter权限提升

CVE-2023-32233 NetFilter权限提升 Netfilter是Linux 内核中的网络数据包处理框架(iptables)通过各种规则和过滤器,基于数据包的来源、目标地址、协议类型、端口号等信息,控制网络流量和数据包的转发和处理具体,详情请…

调用腾讯云API实现英文识别

目录 1. 作者介绍2. 腾讯云英文识别API介绍2.1 英文识别原理—OCR技术2.2 腾讯云英文识别API 3. 实验过程3.1获得API3.2申请调用接口3.3调试接口3.4实验代码3.5实验结果3.6 问题分析 4. 参考连接 1. 作者介绍 乔奕婕,女,西安工程大学电子信息学院&#…

观澜街道田背西村城市更新项目,开发商保利地产

龙华区观澜街道田背西村保利旧改位于深圳市龙华区田背路与观澜大道交汇处西100米,4号线的北延线茜坑站地铁口物业,毗邻龙华区政府,周边交通便利,毗邻4号线茜坑站,无需换乘,直达深圳北站、福田CBD&#xff1…

明基ew3270u评测

明基EW3270U也是一款拥有4K分辨率的显示器,它采用了一块32英寸VA面板,而4K分辨率则让这么大的屏幕有了细腻的画面呈现效果。HDR技术的加入和较广的色域覆盖,让它拥有较好的画面色彩表现。丰富的的接口,也能让你在使用时获得更好的…

Java之BigDecimal使用

Java之BigDecimal使用 1、BigDecimal概述 ​ BigDecimal用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数,但在实际应用中,可能需要对更大或者更小的数进行运算和处理。一般情况下,对于那些不需要准确计…

南卡与明基护眼台灯,哪款好?对比测评两款热门的护眼台灯

前言 开学已过一个月了,经过一个暑假视力也得到了反馈,我国青少年儿童的近视率直线上升,而近视的发病原因中,最主要的是环境因素以及遗传导致的,而除了遗传因素影响之外,更影响视力的还是环境因素&#xf…

什么样的护眼灯最有效?南卡护眼台灯对比明基深度评测

前言 随着我国手机,平板,电脑以及各种电子产品的普及使用,越来越多的小孩子过早地接触到了这些产品,现在我国近视发病率非常的高,很多青少年儿童小小年纪就已经出现了高度近视,国家和政府也是越来越重视这…

SaaSBase:什么是明基逐鹿?

作为SaaS产品的发掘者,SaaSBase(saasbase.cn)今天带大家了解一个优秀的HR人力资源软件: 明基逐鹿——以数字化经验为基石,以普及中国企业数字化应用为使命,致力于推动中国企业管理的变革,与客户…