热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

golang常用库:配置文件解析库/管理工具viper使用

golang常用库:配置文件解析库管理工具-viper使用-一、viper简介viper配置管理解析库,是由大神SteveFrancia开发,他在google领导着golang的

一、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命令:

go get github.com/spf13/viper



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



通过viper.Set设置值


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


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

设置默认值



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



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


Examples:


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搜索和读取配置文件例子片段


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。



例子1. 读取配置文件


config.toml 配置文件:


# 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:


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 配置文件:


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

viper_multi.go


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,内容如下:


{
"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 读取配置项的值


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:


# 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文件:


{
"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:


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


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:


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



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


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()则会直接覆盖同名文件。



四、参考



  • viper 文档

  • golang json库gjson的使用




推荐阅读
  • 从 .NET 转 Java 的自学之路:IO 流基础篇
    本文详细介绍了 Java 中的 IO 流,包括字节流和字符流的基本概念及其操作方式。探讨了如何处理不同类型的文件数据,并结合编码机制确保字符数据的正确读写。同时,文中还涵盖了装饰设计模式的应用,以及多种常见的 IO 操作实例。 ... [详细]
  • 本文详细介绍如何使用Python进行配置文件的读写操作,涵盖常见的配置文件格式(如INI、JSON、TOML和YAML),并提供具体的代码示例。 ... [详细]
  • andr ... [详细]
  • 本文详细介绍如何在VSCode中配置自定义代码片段,使其具备与IDEA相似的代码生成快捷键功能。通过具体的Java和HTML代码片段示例,展示配置步骤及效果。 ... [详细]
  • 版本控制工具——Git常用操作(下)
    本文由云+社区发表作者:工程师小熊摘要:上一集我们一起入门学习了git的基本概念和git常用的操作,包括提交和同步代码、使用分支、出现代码冲突的解决办法、紧急保存现场和恢复 ... [详细]
  • 本文详细分析了JSP(JavaServer Pages)技术的主要优点和缺点,帮助开发者更好地理解其适用场景及潜在挑战。JSP作为一种服务器端技术,广泛应用于Web开发中。 ... [详细]
  • 本文详细介绍了Java中org.neo4j.helpers.collection.Iterators.single()方法的功能、使用场景及代码示例,帮助开发者更好地理解和应用该方法。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • PyCharm下载与安装指南
    本文详细介绍如何从官方渠道下载并安装PyCharm集成开发环境(IDE),涵盖Windows、macOS和Linux系统,同时提供详细的安装步骤及配置建议。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • Python自动化处理:从Word文档提取内容并生成带水印的PDF
    本文介绍如何利用Python实现从特定网站下载Word文档,去除水印并添加自定义水印,最终将文档转换为PDF格式。该方法适用于批量处理和自动化需求。 ... [详细]
  • Hadoop入门与核心组件详解
    本文详细介绍了Hadoop的基础知识及其核心组件,包括HDFS、MapReduce和YARN。通过本文,读者可以全面了解Hadoop的生态系统及应用场景。 ... [详细]
  • Java编程实践:深入理解方法重载
    本文介绍了Java中方法重载的概念及其应用。通过多个示例,详细讲解了如何在同一类中定义具有相同名称但不同参数列表的方法,以实现更灵活的功能调用。 ... [详细]
  • 本文将介绍网易NEC CSS框架的规范及其在实际项目中的应用。通过详细解析其分类和命名规则,探讨如何编写高效、可维护的CSS代码,并分享一些实用的学习心得。 ... [详细]
author-avatar
鸟鸟212
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有