Go开发学习 | 如何快速读取json/yaml/ini等格式的配置文件使用示例

发布时间 2023-11-01 15:08:02作者: 天使angl

 

0x00 前言简述

0x01 常用模块

    • encoding/json 模块 - json 配置文件解析

    • gopkg.in/ini.v1 模块 - ini 配置文件解析

    • gopkg.in/yaml.v3 模块 - yaml 配置文件解析

    • spf13/viper 模块 - 配置文件解析终结者

    • 原生map结构 - properties 配置文件解析

0x00 前言简述

描述: 作为开发者相信对应用程序的配置文件并不陌生吧,例如 Java Spring Boot 里的 class 目录中程序配置,当然go语言相关项目也是可以根据配置文件的格式内容进行读取的,常规的配置文件格式有 json、ini、yaml (个人推荐)、properties 等,我们可以使用其为程序配置一些初始化的可变参数,例如 数据库字符串链接以及认证密码等等。

好,下面作者将依次从json、ini、以及yaml、properties 等顺序进行讲解。


0x01 常用模块

encoding/json 模块 - json 配置文件解析

config.json 配置文件示例

  1.  
    {
  2.  
    "app": {
  3.  
    "app_name": "hello-gin",
  4.  
    "app_mode": "dev",
  5.  
    "app_host": "localhost",
  6.  
    "app_port": "8080",
  7.  
    "app_secret": "weiyigeek.top"
  8.  
    },
  9.  
    "log":{
  10.  
    "log_name": "app",
  11.  
    "log_path": "/logs",
  12.  
    "log_age": "180",
  13.  
    "log_rotation_time": "24"
  14.  
    },
  15.  
    "db": {
  16.  
    "mysql": {
  17.  
    "mysql_user": "root",
  18.  
    "mysql_pass": "123456",
  19.  
    "mysql_addr": "localhost",
  20.  
    "mysql_port": "3306",
  21.  
    "mysql_database": "test"
  22.  
    },
  23.  
    "redis": {
  24.  
    "redis_addr": "localhost",
  25.  
    "redis_port": "6379",
  26.  
    "redis_database": "9",
  27.  
    "redis_pass": "123456"
  28.  
    }
  29.  
    }
  30.  
    }

LoadJSONConfig函数进行JSON配置文件读取

  1.  
    package config
  2.  
     
  3.  
    import (
  4.  
    "encoding/json"
  5.  
    "log"
  6.  
    "os"
  7.  
    )
  8.  
     
  9.  
    // 读取 JSON 配置文件
  10.  
    // JSON 配置文件结构体
  11.  
    type AppJSONConfig struct {
  12.  
    AppName string `json:"app_name"`
  13.  
    AppMode string `json:"app_mode"`
  14.  
    AppHost string `json:"app_host"`
  15.  
    AppPort string `json:"app_port"`
  16.  
    AppSecret string `json:"app_secret"`
  17.  
    }
  18.  
     
  19.  
    type LogJSONConfig struct {
  20.  
    LogPath string `json:"log_path"`
  21.  
    LogName string `json:"log_name"`
  22.  
    LogAge string `json:"log_age"`
  23.  
    LogRotationTime string `json:"log_rotation_time"`
  24.  
    }
  25.  
     
  26.  
    type DbMySQLJSONConfig struct {
  27.  
    User string `json:"mysql_user"`
  28.  
    Pass string `json:"mysql_pass"`
  29.  
    Addr string `json:"mysql_addr"`
  30.  
    Port string `json:"mysql_port"`
  31.  
    Database string `json:"mysql_database"`
  32.  
    }
  33.  
    type DbRedisJSONConfig struct {
  34.  
    Addr string `json:"redis_addr"`
  35.  
    Port string `json:"redis_port"`
  36.  
    Pass string `json:"redis_pass"`
  37.  
    Database string `json:"redis_database"`
  38.  
    }
  39.  
    type DbJSONConfig struct {
  40.  
    Mysql DbMySQLJSONConfig `json:"mysql"`
  41.  
    Redis DbRedisJSONConfig `json:"redis"`
  42.  
    }
  43.  
     
  44.  
    type JSONConfig struct {
  45.  
    App AppJSONConfig `json:"app"`
  46.  
    Log LogJSONConfig `json:"log"`
  47.  
    Db DbJSONConfig `json:"db"`
  48.  
    }
  49.  
     
  50.  
    func LoadJSONConfig(path string) *JSONConfig {
  51.  
    // 定义局部变量
  52.  
    var Config JSONConfig
  53.  
     
  54.  
    // 打开配置文件
  55.  
    f, err := os.Open(path)
  56.  
    if err != nil {
  57.  
    log.Printf("Open config file failed!")
  58.  
    panic(err)
  59.  
    }
  60.  
    // 程序结束时关闭打开的文件
  61.  
    defer f.Close()
  62.  
     
  63.  
    // NewDecoder创建一个从file读取并解码json对象的*Decoder,解码器有自己的缓冲,并可能超前读取部分json数据。
  64.  
    decoder := json.NewDecoder(f)
  65.  
    // Decode从输入流读取下一个json编码值并保存在v指向的值里(关键点)
  66.  
    decode_err := decoder.Decode(&Config)
  67.  
    if err != nil {
  68.  
    panic(decode_err)
  69.  
    }
  70.  
    return &Config
  71.  
    }

函数执行入口:

  1.  
    // 声明当前文件属于哪个包,如果是主文件,则写成main
  2.  
    package main
  3.  
     
  4.  
    // 导入gin包
  5.  
    import (
  6.  
    "fmt"
  7.  
    "hello-gin/util/config"
  8.  
    )
  9.  
     
  10.  
    func main() {
  11.  
    conf := config.LoadJSONConfig()
  12.  
    fmt.Print(conf, "\n")
  13.  
    fmt.Println("----------------------------------")
  14.  
    fmt.Println("应用名称", conf.App.AppName)
  15.  
    fmt.Println("应用密钥", conf.App.AppSecret)
  16.  
    }

执行结果:

  1.  
    > go run .\main.go
  2.  
    &{{hello-gin dev localhost 8080 weiyigeek.top} {/logs app debug} {{root 123456 localhost 3306 test} {localhost 6379 123456 9}}}
  3.  
    ----------------------------------
  4.  
    应用名称 hello-gin
  5.  
    应用密钥 weiyigeek.top

gopkg.in/ini.v1 模块 - ini 配置文件解析

在Go中读取INI文件,我们可以使用名为go-ini的第三方库(a third-party library),它是一个非常方便、高效的go配置文件操作库。

模块下载: go get -v -u gopkg.in/ini.v1

config.ini 配置文件示例:

  1.  
    [app]
  2.  
    name="hellogin"
  3.  
    mode="dev"
  4.  
    host="localhost"
  5.  
    port=8080
  6.  
    secret="weiyigeek"
  7.  
     
  8.  
    [log]
  9.  
    name="ginDemo"
  10.  
    path="D:/Study/Project/Go/hello-gin/logs"
  11.  
    maxage=180
  12.  
    rotation_time=24
  13.  
    rotation_size=100
  14.  
     
  15.  
    [mysql]
  16.  
    host=192.168.2.2
  17.  
    port=3306
  18.  
    user=weiyigeek
  19.  
    pass=123456
  20.  
    database=weiyigeek
  21.  
     
  22.  
    [redis]
  23.  
    host=192.168.2.6
  24.  
    port=6379
  25.  
    pass=weiyigeek.top
  26.  
    database=10

LoadINIConfig 读取ini配置文件函数

  1.  
    package config
  2.  
     
  3.  
    import (
  4.  
    "fmt"
  5.  
    "gopkg.in/ini.v1"
  6.  
    )
  7.  
     
  8.  
    // 创建ini配置文件中相关的字段结构体
  9.  
    type AppINIConfig struct {
  10.  
    AppName string `ini:"name"`
  11.  
    AppMode string `ini:"mode"`
  12.  
    AppHost string `ini:"host"`
  13.  
    AppPort int `ini:"port"`
  14.  
    AppSecret string `ini:"secret"`
  15.  
    }
  16.  
     
  17.  
    type LogINIConfig struct {
  18.  
    LogPath string `ini:"path"`
  19.  
    LogName string `ini:"name"`
  20.  
    LogAge int `ini:"age"`
  21.  
    LogRotationTime int `ini:"rotation_time"`
  22.  
    LogRotationSize int `ini:"rotation_size"`
  23.  
    }
  24.  
     
  25.  
    type DbMysqlINIConfig struct {
  26.  
    User string `ini:"user"`
  27.  
    Pass string `ini:"pass"`
  28.  
    Host string `ini:"addr"`
  29.  
    Port int `ini:"port"`
  30.  
    Database string `ini:"database"`
  31.  
    }
  32.  
     
  33.  
    type DbRedisINIConfig struct {
  34.  
    Host string `ini:"addr"`
  35.  
    Port int `ini:"port"`
  36.  
    Pass string `ini:"pass"`
  37.  
    Database string `ini:"database"`
  38.  
    }
  39.  
     
  40.  
    type INIConfig struct {
  41.  
    App AppINIConfig `ini:"app"`
  42.  
    Log LogINIConfig `ini:"log"`
  43.  
    DbMysql DbMysqlINIConfig `ini:"mysql"`
  44.  
    DbRedis DbMysqlINIConfig `ini:"redis"`
  45.  
    }
  46.  
     
  47.  
    func LoadINIConfig(path string) *INIConfig {
  48.  
    // 0.实例化结构体
  49.  
    config := &INIConfig{}
  50.  
     
  51.  
    // 1.加载配置文件
  52.  
    cfg, err := ini.Load(path)
  53.  
    if err != nil {
  54.  
    fmt.Println("配置文件读取错误,请检查文件路径:", err)
  55.  
    panic(err)
  56.  
    }
  57.  
     
  58.  
    // 2.读取配置文件各章节下的KV配置值,并设定默认默认值。
  59.  
    config.App.AppName = cfg.Section("app").Key("name").String()
  60.  
    config.App.AppMode = cfg.Section("app").Key("mode").MustString("dev")
  61.  
    config.App.AppHost = cfg.Section("app").Key("host").MustString("localhost")
  62.  
    config.App.AppPort = cfg.Section("app").Key("port").MustInt(8080)
  63.  
    config.App.AppSecret = cfg.Section("app").Key("secret").String()
  64.  
     
  65.  
    config.Log.LogName = cfg.Section("log").Key("name").String()
  66.  
    config.Log.LogPath = cfg.Section("log").Key("path").String()
  67.  
    config.Log.LogAge = cfg.Section("log").Key("maxage").MustInt(180)
  68.  
    config.Log.LogRotationSize = cfg.Section("log").Key("rotation_time").MustInt(24)
  69.  
    config.Log.LogRotationTime = cfg.Section("log").Key("rotation_size").MustInt(100)
  70.  
     
  71.  
    config.DbMysql.Host = cfg.Section("mysql").Key("host").String()
  72.  
    config.DbMysql.Port = cfg.Section("mysql").Key("port").MustInt(3306)
  73.  
    config.DbMysql.User = cfg.Section("mysql").Key("user").String()
  74.  
    config.DbMysql.Pass = cfg.Section("mysql").Key("pass").String()
  75.  
    config.DbMysql.Database = cfg.Section("mysql").Key("database").String()
  76.  
     
  77.  
    config.DbRedis.Host = cfg.Section("redis").Key("host").String()
  78.  
    config.DbRedis.Port = cfg.Section("redis").Key("port").MustInt(6379)
  79.  
    config.DbRedis.Pass = cfg.Section("redis").Key("pass").String()
  80.  
    config.DbRedis.Database = cfg.Section("redis").Key("database").String()
  81.  
    return config
  82.  
    }

main 函数入口调用

  1.  
    // 声明当前文件属于哪个包,如果是主文件,则写成main
  2.  
    package main
  3.  
     
  4.  
    // 导入gin包
  5.  
    import (
  6.  
    "fmt"
  7.  
    "hello-gin/util/config"
  8.  
    )
  9.  
     
  10.  
    func main() {
  11.  
    confINI := config.LoadINIConfig("configs/config.ini")
  12.  
    fmt.Println(confINI)
  13.  
    fmt.Println("App : ", confINI.App)
  14.  
    fmt.Println("Log : ", confINI.Log)
  15.  
    fmt.Println("Database :", confINI.DbRedis.Database)
  16.  
    }

执行结果:

  1.  
    go run .\main.go
  2.  
    &{{hellogin dev localhost 8080 weiyigeek} {D:/Study/Project/Go/hello-gin/logs ginDemo 180 100 24} {weiyigeek 123456 192.168.2.2 3306 weiyigeek} { weiyigeek.top 192.168.2.6 6379 10}}
  3.  
    App : {hellogin dev localhost 8080 weiyigeek}
  4.  
    Log : {D:/Study/Project/Go/hello-gin/logs ginDemo 180 100 24}
  5.  
    Database : 10

gopkg.in/yaml.v3 模块 - yaml 配置文件解析

描述: gopkg.in/yaml.v3 包使Go程序能够轻松地对yaml值进行编码和解码, 它是作为juju项目的一部分在Canonical中开发的,基于著名的libyaml C库的纯Go端口,可以快速可靠地解析和生成YAML数据。

项目地址: https://github.com/go-yaml/yaml

模块包下载: go get -v -u gopkg.in/yaml.v3

config.yaml 配置文件示例

  1.  
    app:
  2.  
    name: "hellogin"
  3.  
    mode: "dev"
  4.  
    host: "localhost"
  5.  
    port: "8080"
  6.  
    secret: "weiyigeek"
  7.  
    log:
  8.  
    name: "ginDemo"
  9.  
    path: "D:/Study/Project/Go/hello-gin/logs"
  10.  
    maxage: 180
  11.  
    rotation_time: 24
  12.  
    rotation_size: 100
  13.  
    db:
  14.  
    mysql:
  15.  
    host: 192.168.2.2
  16.  
    port: 3306
  17.  
    user: weiyigeek
  18.  
    pass: 123456
  19.  
    database: weiyigeek
  20.  
    redis:
  21.  
    host: 192.168.2.6
  22.  
    port: 3306
  23.  
    pass: weiyigeek.top
  24.  
    database: 10
  25.  
    user:
  26.  
    user:
  27.  
    - weiyigeek
  28.  
    - geeker
  29.  
     
  30.  
    mqtt:
  31.  
    host: 192.168.2.7:1883
  32.  
    username: weiyigeek
  33.  
    password: weiyigeek.top

LoadYAMLConfig 函数读取yaml配置文件

  1.  
    package config
  2.  
     
  3.  
    import (
  4.  
    "fmt"
  5.  
    "io/ioutil"
  6.  
    "log"
  7.  
     
  8.  
    "gopkg.in/yaml.v3"
  9.  
    )
  10.  
     
  11.  
    // 读取yaml配置文件
  12.  
    // YAML 配置文件结构体
  13.  
    type AppYAMLConfig struct {
  14.  
    AppName string `yaml:"name"`
  15.  
    AppMode string `yaml:"mode"`
  16.  
    AppHost string `yaml:"host"`
  17.  
    AppPort string `yaml:"port"`
  18.  
    AppSecret string `yaml:"secret"`
  19.  
    }
  20.  
     
  21.  
    type LogYAMLConfig struct {
  22.  
    LogPath string `yaml:"path"`
  23.  
    LogName string `yaml:"name"`
  24.  
    LogAge string `yaml:"age"`
  25.  
    LogRotationTime string `yaml:"rotation_time"`
  26.  
    LogRotationSize string `yaml:"rotation_size"`
  27.  
    }
  28.  
     
  29.  
    type DbMySQLYAMLConfig struct {
  30.  
    User string `yaml:"user"`
  31.  
    Pass string `yaml:"pass"`
  32.  
    Addr string `yaml:"addr"`
  33.  
    Port string `yaml:"port"`
  34.  
    Database string `yaml:"database"`
  35.  
    }
  36.  
    type DbRedisYAMLConfig struct {
  37.  
    Addr string `yaml:"addr"`
  38.  
    Port string `yaml:"port"`
  39.  
    Pass string `yaml:"pass"`
  40.  
    Database string `yaml:"database"`
  41.  
    }
  42.  
    type DbYAMLConfig struct {
  43.  
    Mysql DbMySQLYAMLConfig `yaml:"mysql"`
  44.  
    Redis DbRedisYAMLConfig `yaml:"redis"`
  45.  
    }
  46.  
     
  47.  
    type MqttYAMLconfig struct {
  48.  
    Host string `yaml:"host"`
  49.  
    Username string `yaml:"username"`
  50.  
    Password string `yaml:"password"`
  51.  
    }
  52.  
     
  53.  
    type UserYAMLconfig struct {
  54.  
    User []string `yaml:"user"`
  55.  
    Mqtt MqttYAMLconfig `yaml:"mqtt"`
  56.  
    }
  57.  
     
  58.  
    type YAMLConfig struct {
  59.  
    App AppYAMLConfig `yaml:"app"`
  60.  
    Log LogYAMLConfig `yaml:"log"`
  61.  
    Db DbYAMLConfig `yaml:"db"`
  62.  
    User UserYAMLconfig `yaml:"user"`
  63.  
    }
  64.  
     
  65.  
    func LoadYAMLConfig(path string) *YAMLConfig {
  66.  
    // 定义局部变量
  67.  
    config := &YAMLConfig{}
  68.  
     
  69.  
    // 打开并读取yaml配置文件
  70.  
    yamlFile, err := ioutil.ReadFile(path)
  71.  
    if err != nil {
  72.  
    log.Printf("Open config.yaml failed!")
  73.  
    panic(err)
  74.  
    }
  75.  
     
  76.  
    // 使用yaml中Unmarshal方法,解析yaml配置文件并绑定定义的结构体
  77.  
    err = yaml.Unmarshal(yamlFile, config)
  78.  
    if err != nil {
  79.  
    log.Printf("yaml config file Unmarsha failed!")
  80.  
    panic(err)
  81.  
    }
  82.  
     
  83.  
    return config
  84.  
    }

入口函数:

  1.  
    // 声明当前文件属于哪个包,如果是主文件,则写成main
  2.  
    package main
  3.  
     
  4.  
    // 导入gin包
  5.  
    import (
  6.  
    "fmt"
  7.  
    "hello-gin/util/config"
  8.  
    )
  9.  
     
  10.  
    func main() {
  11.  
    confYAML := config.LoadYAMLConfig("configs/config.yaml")
  12.  
    fmt.Print(confYAML, "\n")
  13.  
    fmt.Println("--------------------------------------------------------------")
  14.  
    fmt.Println("应用用户", confYAML.User.User)
  15.  
    fmt.Println("应用名称", confYAML.App.AppName)
  16.  
    fmt.Println("应用密钥", confYAML.App.AppSecret)
  17.  
    fmt.Println("MySQL账号密码:", confYAML.Db.Mysql.User, confYAML.Db.Mysql.Pass)
  18.  
    }

执行结果:

  1.  
    &{{hellogin dev localhost 8080 weiyigeek} {D:/Study/Project/Go/hello-gin/logs ginDemo 24 100} {{weiyigeek 123456 3306 weiyigeek} { 3306 weiyigeek.top 10}} {[weiyigeek geeker] {192.168.2.7:1883 weiyigeek weiyigeek.top}}}
  2.  
    --------------------------------------------------------------
  3.  
    应用用户 [weiyigeek geeker]
  4.  
    应用名称 hellogin
  5.  
    应用密钥 weiyigeek

spf13/viper 模块 - 配置文件解析终结者

描述: 在前面实践中作者分别用了三种模块包以原生包针对四种不同配置的文件,那到底有没有引入一个包就可以全部解析的呢? 既然这么问,那答案显然是可以的, 那就是今天的主人公 viper 项目地址: github.com/spf13/viper

viper 适用于Go应用程序(包括[Twelve-Factor App)的完整配置解决方案,它被设计用于在应用程序中工作,并且可以处理所有类型的配置需求和格式,它支持以下特性:

  • 设置默认值以及显式配置值

  • 从JSON、TOML、YAML、HCL、envfile和Java properties格式的配置文件读取配置信息

    var SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"}

  • 实时监控和重新读取配置文件(可选)

  • 从环境变量中读取

  • 从远程配置系统(etcd或Consul)读取并监控配置变化

    var SupportedRemoteProviders = []string{"etcd", "etcd3", "consul", "firestore"}

  • 从命令行参数读取配置

  • 从buffer读取配置

Viper 优先级

  • 显示调用Set设置值

  • 命令行参数(flag)

  • 环境变量

  • 配置文件

  • key/value存储

  • 默认值

PS: 目前Viper配置的键(Key)是大小写不敏感的。

模块下载安装: go get github.com/spf13/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{}

温馨提示: 每一个Get方法在找不到值的时候都会返回零值, 为了检查给定的键是否存在,提供了IsSet()方法.

参考地址: https://github.com/spf13/viper/blob/master/README.md


偷偷的告诉你哟?极客全栈修炼】微信小程序已经上线了,

可直接在微信里面直接浏览博主博客了哟,后续将上线更多有趣的小工具。


常规使用

  1.  
    // # 如果没有通过配置文件、环境变量、远程配置或命令行标志(flag)设置键,则默认值非常有用。
  2.  
    viper.SetDefault("ContentDir", "content")
  3.  
    viper.SetDefault("LayoutDir", "layouts")
  4.  
    viper.SetDefault("Taxonomies", map[string]string{"tag": "tags", "category": "categories"})
  5.  
     
  6.  
    // # Viper支持JSON、TOML、YAML、HCL、envfile和Java properties格式的配置文件
  7.  
    // 方式1
  8.  
    viper.SetConfigFile("config.yaml") // 指定配置文件路径
  9.  
    viper.AddConfigPath("/etc/appname/") // 查找配置文件所在的路径
  10.  
     
  11.  
    // 方式2
  12.  
    viper.SetConfigName("config") // 配置文件名称(无扩展名)
  13.  
    viper.SetConfigType("yaml") // 如果配置文件的名称中没有扩展名,则需要配置此项
  14.  
    viper.AddConfigPath("/etc/appname/") // 查找配置文件所在的路径
  15.  
    viper.AddConfigPath("$HOME/.appname") // 多次调用以添加多个搜索路径
  16.  
    viper.AddConfigPath(".") // 还可以在工作目录中查找配置
  17.  
     
  18.  
    // # 通过 ReadInConfig 函数,寻找配置文件并读取,操作的过程中可能会发生错误,如配置文件没找到,配置文件的内容格式不正确等;
  19.  
    if err := viper.ReadInConfig(); err != nil {
  20.  
    if _, ok := err.(viper.ConfigFileNotFoundError); ok {
  21.  
    // 配置文件未找到错误;如果需要可以忽略
  22.  
    } else {
  23.  
    // 配置文件被找到,但产生了另外的错误
  24.  
    }
  25.  
    } else {
  26.  
    // 配置文件找到并成功解析
  27.  
    }
  28.  
     
  29.  
    // # Viper 覆盖设置
  30.  
    viper.Set("Verbose", true)
  31.  
    viper.Set("LogFile", LogFile)
  32.  
     
  33.  
     
  34.  
    // # 通过 ReadInConfig 函数,寻找配置文件并读取,操作的过程中可能会发生错误,如配置文件没找到,配置文件的内容格式不正确等;
  35.  
    fmt.Println(viper.Get("mysql")) // map[port:3306 url:127.0.0.1]
  36.  
    fmt.Println(viper.Get("mysql.url")) // 127.0.0.1
  37.  
     
  38.  
    // # 使用viper函数获取嵌套的键的值
  39.  
    {
  40.  
    "host": {
  41.  
    "address": "localhost",
  42.  
    "port": 5799
  43.  
    },
  44.  
    "datastore": {
  45.  
    "mysql": {
  46.  
    "host": "127.0.0.1",
  47.  
    "port": 3306
  48.  
    }
  49.  
    }
  50.  
    }
  51.  
     
  52.  
    viper.GetString("datastore.mysql.host") // (返回 "127.0.0.1")
  53.  
     
  54.  
    // # 获取子树值
  55.  
    app:
  56.  
    cache1:
  57.  
    max-items: 100
  58.  
    item-size: 64
  59.  
    cache2:
  60.  
    max-items: 200
  61.  
    item-size: 80
  62.  
     
  63.  
    subv := viper.Sub("app.cache1")
  64.  
     
  65.  
    // # viper加载完配置信息后使用结构体变量保存配置信息
  66.  
    type Config struct {
  67.  
    Port int `mapstructure:"port"`
  68.  
    Version string `mapstructure:"version"`
  69.  
    }
  70.  
    var Conf = new(Config)
  71.  
    // 将读取的配置信息保存至全局变量Conf
  72.  
    if err := viper.Unmarshal(Conf); err != nil {
  73.  
    panic(fmt.Errorf("unmarshal conf failed, err:%s \n", err))
  74.  
    }
  75.  
     
  76.  
    // # 使用WatchConfig监控配置文件变化
  77.  
    viper.WatchConfig()
  78.  
    // 注意!!!配置文件发生变化后要同步到全局变量Conf
  79.  
    viper.OnConfigChange(func(in fsnotify.Event) {
  80.  
    fmt.Println("配置文件被修改了")
  81.  
    if err := viper.Unmarshal(Conf); err != nil {
  82.  
    panic(fmt.Errorf("unmarshal conf failed, err:%s \n", err))
  83.  
    }
  84.  
    })

示例1.Viper支持Cobra库中使用的Pflag绑定并输出

  1.  
    package main
  2.  
     
  3.  
    import (
  4.  
    "flag"
  5.  
    "fmt"
  6.  
     
  7.  
    "github.com/spf13/pflag"
  8.  
    "github.com/spf13/viper"
  9.  
    )
  10.  
     
  11.  
    func main() {
  12.  
    // 使用标准库 "flag" 包
  13.  
    flag.Int("flagname", 1234, "help message for flagname")
  14.  
     
  15.  
    // pflag 包可以通过导入这些 flags 来处理flag包定义的flags, pflag 包可以通过导入这些 flags 来处理flag包定义的flags
  16.  
    pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
  17.  
    pflag.Parse()
  18.  
     
  19.  
    // viper 绑定到标志
  20.  
    viper.BindPFlags(pflag.CommandLine)
  21.  
     
  22.  
    // 从 viper 检索值
  23.  
    i := viper.GetInt("flagname")
  24.  
    fmt.Println(i) // 1234
  25.  
    }

示例2.使用viper读取yaml并存放在结构体中

configs\prod.yaml 配置文件

  1.  
    app:
  2.  
    name: "hellogin"
  3.  
    mode: "dev"
  4.  
    host: "localhost"
  5.  
    port: "8080"
  6.  
    secret: "weiyigeek"
  7.  
    version: "v1.2.0"
  8.  
    log:
  9.  
    name: "ginDemo"
  10.  
    path: "D:/Study/Project/Go/hello-gin/logs"
  11.  
    maxage: 180
  12.  
    rotation_time: 24
  13.  
    rotation_size: 100
  14.  
    db:
  15.  
    mysql:
  16.  
    host: 192.168.2.2
  17.  
    port: 3306
  18.  
    user: weiyigeek
  19.  
    pass: 123456
  20.  
    database: weiyigeek
  21.  
    redis:
  22.  
    host: 192.168.2.6
  23.  
    port: 3306
  24.  
    pass: weiyigeek.top
  25.  
    database: 10

代码示例:

  1.  
    // go get -v -u gopkg.in/yaml.v3
  2.  
    package main
  3.  
     
  4.  
    import (
  5.  
    "fmt"
  6.  
    "github.com/fsnotify/fsnotify"
  7.  
    "github.com/spf13/viper"
  8.  
    )
  9.  
     
  10.  
    // YAML 配置文件KV结构体
  11.  
    type AppYAMLConfig struct {
  12.  
    AppName string `mapstructure:"name"`
  13.  
    AppMode string `mapstructure:"mode"`
  14.  
    AppHost string `mapstructure:"host"`
  15.  
    AppPort string `mapstructure:"port"`
  16.  
    AppSecret string `mapstructure:"secret"`
  17.  
    AppVersion string `mapstructure:"version"`
  18.  
    }
  19.  
     
  20.  
    type LogYAMLConfig struct {
  21.  
    LogPath string `mapstructure:"path"`
  22.  
    LogName string `mapstructure:"name"`
  23.  
    LogAge string `mapstructure:"age"`
  24.  
    LogRotationTime string `mapstructure:"rotation_time"`
  25.  
    LogRotationSize string `mapstructure:"rotation_size"`
  26.  
    }
  27.  
     
  28.  
    type DbMySQLYAMLConfig struct {
  29.  
    User string `mapstructure:"user"`
  30.  
    Pass string `mapstructure:"pass"`
  31.  
    Addr string `mapstructure:"addr"`
  32.  
    Port string `mapstructure:"port"`
  33.  
    Database string `mapstructure:"database"`
  34.  
    }
  35.  
    type DbRedisYAMLConfig struct {
  36.  
    Addr string `mapstructure:"addr"`
  37.  
    Port string `mapstructure:"port"`
  38.  
    Pass string `mapstructure:"pass"`
  39.  
    Database string `mapstructure:"database"`
  40.  
    }
  41.  
    type DbYAMLConfig struct {
  42.  
    Mysql DbMySQLYAMLConfig `mapstructure:"mysql"`
  43.  
    Redis DbRedisYAMLConfig `mapstructure:"redis"`
  44.  
    }
  45.  
     
  46.  
    type MqttYAMLconfig struct {
  47.  
    Host string `mapstructure:"host"`
  48.  
    Username string `mapstructure:"username"`
  49.  
    Password string `mapstructure:"password"`
  50.  
    }
  51.  
     
  52.  
    type YAMLConfig struct {
  53.  
    App AppYAMLConfig `mapstructure:"app"`
  54.  
    Log LogYAMLConfig `mapstructure:"log"`
  55.  
    Db DbYAMLConfig `mapstructure:"db"`
  56.  
    }
  57.  
     
  58.  
    // viper对象示例化与配置文件读取
  59.  
    func NewConfig(name string) *viper.Viper {
  60.  
    // 设置实例化viper对象
  61.  
    vp := viper.New()
  62.  
    // 设置配置文件名,没有后缀
  63.  
    vp.SetConfigName(name)
  64.  
    // 设置读取文件格式为: yaml
  65.  
    vp.SetConfigType("yaml")
  66.  
    // 设置配置文件目录(可以设置多个,优先级根据添加顺序来)
  67.  
    vp.AddConfigPath("./configs/")
  68.  
     
  69.  
    // 读取配置文件并解析
  70.  
    if err := vp.ReadInConfig(); err != nil {
  71.  
    if _, ok := err.(viper.ConfigFileNotFoundError); ok {
  72.  
    fmt.Printf("配置文件未找到!%v\n", err)
  73.  
    return nil
  74.  
    } else {
  75.  
    fmt.Printf("找到配置文件,但是解析错误,%v\n", err)
  76.  
    return nil
  77.  
    }
  78.  
    }
  79.  
    // 绑定返回结构体对象
  80.  
    return vp
  81.  
    }
  82.  
     
  83.  
    func main() {
  84.  
    // 实例化 vp 对象
  85.  
    vp := NewConfig("prod")
  86.  
     
  87.  
    // 获取指定key值
  88.  
    fmt.Println("Version : ", vp.Get("app.version"))
  89.  
     
  90.  
    // 获取指定节值返回map数据类型
  91.  
    fmt.Println(vp.GetStringMap("app"))
  92.  
    v := vp.GetStringMap("app")
  93.  
    fmt.Println("version : ", v["version"], "\n")
  94.  
     
  95.  
    // 将获取到的数据绑定到结构体
  96.  
    conf := new(YAMLConfig)
  97.  
    if err := vp.Unmarshal(conf); err != nil {
  98.  
    fmt.Printf("解析错误: %v\n", err)
  99.  
    panic(err)
  100.  
    }
  101.  
    fmt.Println(conf, "\n")
  102.  
     
  103.  
    // 监控配置文件的变化
  104.  
    // # 使用WatchConfig监控配置文件变化
  105.  
    vp.WatchConfig()
  106.  
    // 注意!!!配置文件发生变化后要同步到全局变量Conf
  107.  
    vp.OnConfigChange(func(in fsnotify.Event) {
  108.  
    fmt.Println("配置文件被修改了")
  109.  
    if err := vp.Unmarshal(conf); err != nil {
  110.  
    panic(fmt.Errorf("unmarshal conf failed, err:%s \n", err))
  111.  
    }
  112.  
    })
  113.  
    fmt.Println(vp)
  114.  
    }

执行结果:

  1.  
    go run .\main.go
  2.  
    Version : v1.2.0
  3.  
    map[host:localhost mode:dev name:hellogin port:8080 secret:weiyigeek version:v1.2.0]
  4.  
    version : v1.2.0
  5.  
     
  6.  
    &{{hellogin dev localhost 8080 weiyigeek v1.2.0} {D:/Study/Project/Go/hello-gin/logs ginDemo 24 100} {{weiyigeek 123456 3306 weiyigeek} { 3306 weiyigeek.top 10}}}
  7.  
     
  8.  
    &{. [D:\Study\Project\Go\hello-gin\configs] 0x1235c48 [] prod D:\Study\Project\Go\hello-gin\configs\prod.yaml yaml 420 {false false false false false false false false false false false false false false false [] false <nil> 0 false
  9.  
    false} false <nil> false map[app:map[host:localhost mode:dev name:hellogin port:8080 secret:weiyigeek version:v1.2.0] db:map[mysql:map[database:weiyigeek host:192.168.2.2 pass:123456 port:3306 user:weiyigeek] redis:map[database:10 host:192.168.2.6 pass:weiyigeek.top port:3306]] log:map[maxage:180 name:ginDemo path:D:/Study/Project/Go/hello-gin/logs rotation_size:100 rotation_time:24]] map[] map[] map[] map[] map[] map[] false 0xfa25a0 {} 0xc000066860 0xc000066880}

原生map结构 - properties 配置文件解析

properties 配置文件

  1.  
    appName=hellogin
  2.  
    appMode=dev
  3.  
    appHost=localhost
  4.  
    appPort=8080
  5.  
    appSecret="WeiyiGeek"
  6.  
     
  7.  
    logName="ginDemo"
  8.  
    logPath="D:/Study/Project/Go/hello-gin/logs"
  9.  
    logMaxage=180
  10.  
    logRotationTime=24
  11.  
    logRotationSize=100

亲,文章就要看完了,不关注一下作者吗?

 

LoadPropConfig 函数读取properties配置文件

  1.  
    package config
  2.  
     
  3.  
    import (
  4.  
    "bufio"
  5.  
    "fmt"
  6.  
    "io"
  7.  
    "os"
  8.  
    "strings"
  9.  
    )
  10.  
     
  11.  
    var properties = make(map[string]string)
  12.  
     
  13.  
    func LoadPropConfig(path string) map[string]string {
  14.  
    propFile, err := os.OpenFile(path, os.O_RDONLY, 0666)
  15.  
    if err != nil {
  16.  
    fmt.Println("打开 config.properties 配置文件失败!")
  17.  
    panic(err)
  18.  
    }
  19.  
     
  20.  
    propReader := bufio.NewReader(propFile)
  21.  
    for {
  22.  
    prop, err := propReader.ReadString('\n')
  23.  
    if err != nil {
  24.  
    if err == io.EOF {
  25.  
    break
  26.  
    }
  27.  
    }
  28.  
    // 此处注意不要出现Yoda conditions问题
  29.  
    if (len(prop) == 0) || (prop == "\n") {
  30.  
    continue
  31.  
    }
  32.  
    properties[strings.Replace(strings.Split(prop, "=")[0], " ", "", -1)] = strings.Replace(strings.Split(prop, "=")[1], " ", "", -1)
  33.  
    }
  34.  
     
  35.  
    return properties
  36.  
    }

函数调用主入口

  1.  
    // 声明当前文件属于哪个包,如果是主文件,则写成main
  2.  
    package main
  3.  
     
  4.  
    // 导入gin包
  5.  
    import (
  6.  
    "fmt"
  7.  
    "hello-gin/util/config"
  8.  
    )
  9.  
     
  10.  
    func main() {
  11.  
    properties := config.LoadPropConfig("configs/config.properties")
  12.  
    fmt.Println(properties)
  13.  
    fmt.Print("AppName : ", properties["appName"])
  14.  
    fmt.Println("LogPath : ", properties["logPath"])
  15.  
    }

执行结果:

  1.  
    $ go run .\main.go
  2.  
    map[appHost:localhost
  3.  
    appMode:dev
  4.  
    appName:hellogin
  5.  
    appPort:8080
  6.  
    appSecret:"WeiyiGeek"
  7.  
    logMaxage:180
  8.  
    logName:"ginDemo"
  9.  
    logPath:"D:/Study/Project/Go/hello-gin/logs"
  10.  
    logRotationTime:24
  11.  
    ]
  12.  
    AppName : hellogin
  13.  
    LogPath : "D:/Study/Project/Go/hello-gin/logs"

本文至此完毕,更多技术文章,尽情等待下篇好文!

原文地址: https://blog.weiyigeek.top/2023/4-18-731.html

如果此篇文章对你有帮助,请你将它分享给更多的人! 

da08b27ba0839b3cb43063f19b89b941.gif

bae338adcd377a020625e0b32bf8d857.png 学习书籍推荐 往期发布文章 1bbde2d4d5b4e63e07b1eff9ad1a4d8a.png

公众号回复【0008】获取【Ubuntu22.04安装与加固建脚本】

公众号回复【10001】获取【WinServer安全加固脚本】

公众号回复【1000】获取【PowerShell操作FTP脚本】

公众号回复【0015】获取【Jenkins学习之路汇总】

 热文推荐  

欢迎长按(扫描)二维码 取更多渠道哟!

欢迎关注 【全栈工程师修炼指南】(^U^)ノ~YO

== 全栈工程师修炼指南 ==

微信沟通交流: weiyigeeker 

关注回复【学习交流群】即可加入【安全运维沟通交流小群

温馨提示: 由于作者水平有限,本章错漏缺点在所难免,希望读者批评指正,若有问题或建议请在文章末尾留下您宝贵的经验知识,或联系邮箱地址

master@weiyigeek.top 或 关注公众号 [全栈工程师修炼指南] 留言。

[全栈工程师修炼指南]  关注 企业运维实践、网络安全、系统运维、应用开发、物联网实战、全栈文章,尽在博客站点,谢谢支持!

点个【 赞 + 在 】看吧!

 点击【"阅读原文"】获取更多有趣的知识!