欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go語(yǔ)言配置解析庫(kù)viper的使用指南

 更新時(shí)間:2023年06月09日 10:12:24   作者:zsx_yiyiyi  
viper?配置管理解析庫(kù),是由大神?Steve?Francia?開(kāi)發(fā),本文就來(lái)和大家詳細(xì)講講它的具體使用,文中的示例代碼講解詳細(xì),需要的可以收藏一下

1、viper簡(jiǎn)介

viper 配置管理解析庫(kù),是由大神 Steve Francia 開(kāi)發(fā),他在google領(lǐng)導(dǎo)著 golang 的產(chǎn)品開(kāi)發(fā),他也是 gohugo.io的創(chuàng)始人之一,命令行解析庫(kù) cobra 開(kāi)發(fā)者。

viper是一個(gè)配置管理的解決方案,它能夠從 json,toml,ini,yaml,hcl,env 等多種格式文件中,讀取配置內(nèi)容,它還能從一些遠(yuǎn)程配置中心讀取配置文件,如consul,etcd等;它還能夠監(jiān)聽(tīng)文件的內(nèi)容變化。

2、viper功能介紹

  • 讀取 json,toml,ini,yaml,hcl,env 等格式的文件內(nèi)容
  • 讀取遠(yuǎn)程配置文件,如 consul,etcd 等和監(jiān)控配置文件變化
  • 讀取命令行 flag 的值
  • 從 buffer 中讀取值

配置文件又可以分為不同的環(huán)境,比如dev,test,prod等。

viper 可以幫助你專(zhuān)注配置文件管理。

viper 讀取配置文件的優(yōu)先順序,從高到低,如下:

  • 顯式設(shè)置的Set函數(shù)
  • 命令行參數(shù)
  • 環(huán)境變量
  • 配置文件
  • 遠(yuǎn)程k-v 存儲(chǔ)系統(tǒng),如consul,etcd等
  • 默認(rèn)值

Viper 配置key是不區(qū)分大小寫(xiě)的。

其實(shí),上面的每一種文件格式,都有一些比較有名的解析庫(kù),如:

toml:https://github.com/BurntSushi/toml

json:json的解析庫(kù)比較多,下面列出幾個(gè)常用的

ini:https://github.com/go-ini/ini 等等單獨(dú)文件格式解析庫(kù)。

但是為啥子要用viper,因?yàn)樗且粋€(gè)綜合文件解析庫(kù),包含了上面所有的文件格式解析,是一個(gè)集合體,少了配

置多個(gè)庫(kù)的煩惱。

3、viper使用

安裝viper命令:

go get github.com/spf13/viper

文檔:

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

3.1 通過(guò)viper.Set設(shè)置值

如果某個(gè)鍵通過(guò)viper.Set設(shè)置了值,那么這個(gè)值讀取的優(yōu)先級(jí)最高

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

3.2 設(shè)置默認(rèn)值

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

viper 支持默認(rèn)值的設(shè)置。如果配置文件、環(huán)境變量、遠(yuǎn)程配置中沒(méi)有設(shè)置鍵值,就可以通過(guò)viper設(shè)置一些默認(rèn)

值。

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

讀取配置文件要求:最少要知道從哪個(gè)位置查找配置文件。用戶(hù)一定要設(shè)置這個(gè)路徑。

viper可以從多個(gè)路徑搜索配置文件,單個(gè)viper實(shí)例只支持單個(gè)配置文件。 viper本身沒(méi)有設(shè)置默認(rèn)的搜索路徑,

需要用戶(hù)自己設(shè)置默認(rèn)路徑。

viper搜索和讀取配置文件例子片段:

viper.SetConfigName("config") // 配置文件的文件名,沒(méi)有擴(kuò)展名,如.yaml,.toml這樣的擴(kuò)展名
viper.SetConfigType("yaml")  // 設(shè)置擴(kuò)展名,在這里設(shè)置文件的擴(kuò)展名,另外如果配置文件的名稱(chēng)沒(méi)有擴(kuò)展名,則需要配置這個(gè)選項(xiàng)
viper.AddConfigPath("/etc/appname/") // 查找配置文件所在路徑
viper.AddConfigPath("$HOME/.appname") // 多次調(diào)用AddConfigPath,可以添加多個(gè)搜索路徑
viper.AddConfigPath(".")             // 還可以在工作目錄中搜索配置文件
err := viper.ReadInConfig()       // 搜索并讀取配置文件
if err != nil { // 處理錯(cuò)誤
  panic(fmt.Errorf("Fatal error config file: %s \n", err))
}

說(shuō)明: 這里執(zhí)行viper.ReadInConfig()之后,viper才能確定到底用哪個(gè)文件,viper按照上面的

AddConfigPath() 進(jìn)行搜索,找到第一個(gè)名為 config.ext (這里的ext代表擴(kuò)展名: 如

json,toml,yaml,yml,ini,prop 等擴(kuò)展名) 的文件后即停止搜索。

如果有多個(gè)名稱(chēng)為config的配置文件,viper怎么搜索呢?它會(huì)按照如下順序搜索

  • 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 {        
        // 配置文件沒(méi)有找到; 如果需要可以忽略
    } else {        
        // 查找到了配置文件但是產(chǎn)生了其它的錯(cuò)誤
    }
}
// 查找到配置文件并解析成功

注意[自1.6起]: 你也可以有不帶擴(kuò)展名的文件,并以編程方式指定其格式。對(duì)于位于用戶(hù)$HOME目錄中的

配置文件沒(méi)有任何擴(kuò)展名,如.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 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() {
	// 把配置文件讀取到結(jié)構(gòu)體上
	var config Config
	viper.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:讀取多個(gè)配置文件

在例子1基礎(chǔ)上多增加一個(gè)json的配置文件,config1.json 配置文件:

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

讀取多個(gè)配置文件:

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("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)
}

運(yùn)行:

# 輸出
read config.toml
config:  {127.0.0.1:3300 {0 192.168.1.1 root root123456}} redis:  127.0.0.1:3300

read config1.json
config:  {127.0.0.1:33000 {3306 127.0.0.1 root 123456}} redis:  127.0.0.1:33000

3.6 例子3:讀取配置項(xiàng)的值

新建文件夾 item, 在里面創(chuàng)建文件 config2.json,內(nèi)容如下:

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

讀取配置項(xiàng)的值:

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

運(yùn)行:

# 輸出
[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 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("config3")
	viper.SetConfigType("json")
	viper.AddConfigPath("cmd")
	// 根據(jù)上面配置加載文件
	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、不加命令行參數(shù)運(yùn)行:

$ go run 004.go
# 輸出
mysql - host:  127.0.0.1 , username:  root , port:  3306
redis - host:  127.0.0.1 , port:  3301

說(shuō)明:redis.port 的值是 3301,是 config.json 配置文件里的值。

2、加命令行參數(shù)運(yùn)行

$ 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

說(shuō)明:加了命令行參數(shù) --redis.port 6666,這時(shí)候redis.port輸出的值為 6666,讀取的是cmd命令行的值。

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

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

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

輸出

Hacker:  true ,hobbies:  [skateboarding snowboarding go] ,jacket:  leather ,age: 35

3.9 例子6:寫(xiě)配置文件

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

package main
import (
	"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)
	}
}

沒(méi)有任何輸出表示生成配置文件成功:

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() 區(qū)別:

如果待生成的文件已經(jīng)存在,那么SafeWriteConfig()就會(huì)報(bào)錯(cuò):

Config File "config.yaml" Already Exists,

而WriteConfig()則會(huì)直接覆蓋同名文件。

以上就是Go語(yǔ)言配置解析庫(kù)viper的使用指南的詳細(xì)內(nèi)容,更多關(guān)于Go viper的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • go mutex互斥鎖使用Lock和Unlock方法占有釋放資源

    go mutex互斥鎖使用Lock和Unlock方法占有釋放資源

    Go號(hào)稱(chēng)是為了高并發(fā)而生的,在高并發(fā)場(chǎng)景下,勢(shì)必會(huì)涉及到對(duì)公共資源的競(jìng)爭(zhēng),當(dāng)對(duì)應(yīng)場(chǎng)景發(fā)生時(shí),我們經(jīng)常會(huì)使用 mutex 的 Lock() 和 Unlock() 方法來(lái)占有或釋放資源,雖然調(diào)用簡(jiǎn)單,但 mutex 的內(nèi)部卻涉及挺多的,本文來(lái)好好研究一下
    2023-09-09
  • go build 通過(guò)文件名后綴實(shí)現(xiàn)不同平臺(tái)的條件編譯操作

    go build 通過(guò)文件名后綴實(shí)現(xiàn)不同平臺(tái)的條件編譯操作

    這篇文章主要介紹了go build 通過(guò)文件名后綴實(shí)現(xiàn)不同平臺(tái)的條件編譯操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • go?map搬遷的實(shí)現(xiàn)

    go?map搬遷的實(shí)現(xiàn)

    本文主要介紹了go?map搬遷的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • Golang Cron 定時(shí)任務(wù)的實(shí)現(xiàn)示例

    Golang Cron 定時(shí)任務(wù)的實(shí)現(xiàn)示例

    這篇文章主要介紹了Golang Cron 定時(shí)任務(wù)的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • 基于golang的輕量級(jí)工作流框架Fastflow

    基于golang的輕量級(jí)工作流框架Fastflow

    這篇文章主要介紹了基于golang的輕量級(jí)工作流框架Fastflow,fastflow 執(zhí)行任務(wù)的過(guò)程會(huì)涉及到幾個(gè)概念:Dag, Task, Action, DagInstance,本文給大家分享完整流程,需要的朋友可以參考下
    2022-05-05
  • 基于Golang實(shí)現(xiàn)內(nèi)存數(shù)據(jù)庫(kù)的示例詳解

    基于Golang實(shí)現(xiàn)內(nèi)存數(shù)據(jù)庫(kù)的示例詳解

    這篇文章主要為大家詳細(xì)介紹了如何基于Golang實(shí)現(xiàn)內(nèi)存數(shù)據(jù)庫(kù),文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的小伙伴可以參考一下
    2023-03-03
  • golang?http請(qǐng)求未釋放造成的錯(cuò)誤問(wèn)題

    golang?http請(qǐng)求未釋放造成的錯(cuò)誤問(wèn)題

    這篇文章主要介紹了golang?http請(qǐng)求未釋放造成的錯(cuò)誤問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Go語(yǔ)言中Redis緩存與本地內(nèi)存緩存實(shí)戰(zhàn)

    Go語(yǔ)言中Redis緩存與本地內(nèi)存緩存實(shí)戰(zhàn)

    在現(xiàn)代高并發(fā)系統(tǒng)中,緩存技術(shù)是提升性能和降低數(shù)據(jù)庫(kù)壓力的關(guān)鍵手段,本文將為大家介紹一下Redis緩存與本地內(nèi)存緩存的具體應(yīng)用,需要的可以了解下
    2025-03-03
  • Golang使用channel實(shí)現(xiàn)一個(gè)優(yōu)雅退出功能

    Golang使用channel實(shí)現(xiàn)一個(gè)優(yōu)雅退出功能

    最近補(bǔ)?Golang?channel?方面八股的時(shí)候發(fā)現(xiàn)用?channel?實(shí)現(xiàn)一個(gè)優(yōu)雅退出功能好像不是很難,之前寫(xiě)的?HTTP?框架剛好也不支持優(yōu)雅退出功能,于是就參考了?Hertz?優(yōu)雅退出方面的代碼,為我的?PIANO?補(bǔ)足了這個(gè)?feature
    2023-03-03
  • Go實(shí)現(xiàn)各類(lèi)限流的方法

    Go實(shí)現(xiàn)各類(lèi)限流的方法

    這篇文章主要介紹了Go實(shí)現(xiàn)各類(lèi)限流的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05

最新評(píng)論