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

news2024/12/22 19:14:02

欢迎关注「全栈工程师修炼指南」公众号

点击 👇 下方卡片 即可关注我哟!

设为星标⭐每天带你 基础入门 到 进阶实践 再到 放弃学习

  花开堪折直须折,莫待无花空折枝 


作者主页:[ https://www.weiyigeek.top ]  

博客:[ https://blog.weiyigeek.top ]

作者安全运维学习答疑交流群:请关注公众号回复【学习交流群


文章目录:

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

{
  "app": {
    "app_name": "hello-gin",
    "app_mode": "dev",
    "app_host": "localhost",
    "app_port": "8080",
    "app_secret": "weiyigeek.top"
  },
  "log":{
    "log_name": "app",
    "log_path": "/logs",
    "log_age": "180",
    "log_rotation_time": "24"
  },
  "db": {
    "mysql": {
      "mysql_user": "root",
      "mysql_pass": "123456",
      "mysql_addr": "localhost",
      "mysql_port": "3306",
      "mysql_database": "test"
    },
    "redis": {
      "redis_addr": "localhost",
      "redis_port": "6379",
      "redis_database": "9",
      "redis_pass": "123456"
    }
  } 
}

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

package config

import (
	"encoding/json"
	"log"
	"os"
)

// 读取 JSON 配置文件
// JSON 配置文件结构体
type AppJSONConfig struct {
	AppName   string `json:"app_name"`
	AppMode   string `json:"app_mode"`
	AppHost   string `json:"app_host"`
	AppPort   string `json:"app_port"`
	AppSecret string `json:"app_secret"`
}

type LogJSONConfig struct {
	LogPath         string `json:"log_path"`
	LogName         string `json:"log_name"`
	LogAge          string `json:"log_age"`
	LogRotationTime string `json:"log_rotation_time"`
}

type DbMySQLJSONConfig struct {
	User     string `json:"mysql_user"`
	Pass     string `json:"mysql_pass"`
	Addr     string `json:"mysql_addr"`
	Port     string `json:"mysql_port"`
	Database string `json:"mysql_database"`
}
type DbRedisJSONConfig struct {
	Addr     string `json:"redis_addr"`
	Port     string `json:"redis_port"`
	Pass     string `json:"redis_pass"`
	Database string `json:"redis_database"`
}
type DbJSONConfig struct {
	Mysql DbMySQLJSONConfig `json:"mysql"`
	Redis DbRedisJSONConfig `json:"redis"`
}

type JSONConfig struct {
	App AppJSONConfig `json:"app"`
	Log LogJSONConfig `json:"log"`
	Db  DbJSONConfig  `json:"db"`
}

func LoadJSONConfig(path string) *JSONConfig {
	// 定义局部变量
	var Config JSONConfig

	// 打开配置文件
	f, err := os.Open(path)
	if err != nil {
		log.Printf("Open config file failed!")
		panic(err)
	}
	// 程序结束时关闭打开的文件
	defer f.Close()

	// NewDecoder创建一个从file读取并解码json对象的*Decoder,解码器有自己的缓冲,并可能超前读取部分json数据。
	decoder := json.NewDecoder(f)
	// Decode从输入流读取下一个json编码值并保存在v指向的值里(关键点)
	decode_err := decoder.Decode(&Config)
	if err != nil {
		panic(decode_err)
	}
	return &Config
}

函数执行入口:

// 声明当前文件属于哪个包,如果是主文件,则写成main
package main

// 导入gin包
import (
	"fmt"
	"hello-gin/util/config"
)

func main() {
	conf := config.LoadJSONConfig()
	fmt.Print(conf, "\n")
	fmt.Println("----------------------------------")
	fmt.Println("应用名称", conf.App.AppName)
	fmt.Println("应用密钥", conf.App.AppSecret)
}

执行结果:

> go run .\main.go
&{{hello-gin dev localhost 8080 weiyigeek.top} {/logs app debug} {{root 123456 localhost 3306 test} {localhost 6379 123456 9}}}
----------------------------------
应用名称 hello-gin
应用密钥 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 配置文件示例:

[app]
name="hellogin"
mode="dev"
host="localhost"
port=8080
secret="weiyigeek"

[log]
name="ginDemo"
path="D:/Study/Project/Go/hello-gin/logs"
maxage=180
rotation_time=24
rotation_size=100

[mysql]
host=192.168.2.2
port=3306
user=weiyigeek
pass=123456
database=weiyigeek

[redis]
host=192.168.2.6
port=6379
pass=weiyigeek.top
database=10

LoadINIConfig 读取ini配置文件函数

package config

import (
	"fmt"
	"gopkg.in/ini.v1"
)

// 创建ini配置文件中相关的字段结构体
type AppINIConfig struct {
	AppName   string `ini:"name"`
	AppMode   string `ini:"mode"`
	AppHost   string `ini:"host"`
	AppPort   int    `ini:"port"`
	AppSecret string `ini:"secret"`
}

type LogINIConfig struct {
	LogPath         string `ini:"path"`
	LogName         string `ini:"name"`
	LogAge          int    `ini:"age"`
	LogRotationTime int    `ini:"rotation_time"`
	LogRotationSize int    `ini:"rotation_size"`
}

type DbMysqlINIConfig struct {
	User     string `ini:"user"`
	Pass     string `ini:"pass"`
	Host     string `ini:"addr"`
	Port     int    `ini:"port"`
	Database string `ini:"database"`
}

type DbRedisINIConfig struct {
	Host     string `ini:"addr"`
	Port     int    `ini:"port"`
	Pass     string `ini:"pass"`
	Database string `ini:"database"`
}

type INIConfig struct {
	App     AppINIConfig     `ini:"app"`
	Log     LogINIConfig     `ini:"log"`
	DbMysql DbMysqlINIConfig `ini:"mysql"`
	DbRedis DbMysqlINIConfig `ini:"redis"`
}

func LoadINIConfig(path string) *INIConfig {
	// 0.实例化结构体
	config := &INIConfig{}

	// 1.加载配置文件
	cfg, err := ini.Load(path)
	if err != nil {
		fmt.Println("配置文件读取错误,请检查文件路径:", err)
		panic(err)
	}

	// 2.读取配置文件各章节下的KV配置值,并设定默认默认值。
	config.App.AppName = cfg.Section("app").Key("name").String()
	config.App.AppMode = cfg.Section("app").Key("mode").MustString("dev")
	config.App.AppHost = cfg.Section("app").Key("host").MustString("localhost")
	config.App.AppPort = cfg.Section("app").Key("port").MustInt(8080)
	config.App.AppSecret = cfg.Section("app").Key("secret").String()

	config.Log.LogName = cfg.Section("log").Key("name").String()
	config.Log.LogPath = cfg.Section("log").Key("path").String()
	config.Log.LogAge = cfg.Section("log").Key("maxage").MustInt(180)
	config.Log.LogRotationSize = cfg.Section("log").Key("rotation_time").MustInt(24)
	config.Log.LogRotationTime = cfg.Section("log").Key("rotation_size").MustInt(100)

	config.DbMysql.Host = cfg.Section("mysql").Key("host").String()
	config.DbMysql.Port = cfg.Section("mysql").Key("port").MustInt(3306)
	config.DbMysql.User = cfg.Section("mysql").Key("user").String()
	config.DbMysql.Pass = cfg.Section("mysql").Key("pass").String()
	config.DbMysql.Database = cfg.Section("mysql").Key("database").String()

	config.DbRedis.Host = cfg.Section("redis").Key("host").String()
	config.DbRedis.Port = cfg.Section("redis").Key("port").MustInt(6379)
	config.DbRedis.Pass = cfg.Section("redis").Key("pass").String()
	config.DbRedis.Database = cfg.Section("redis").Key("database").String()
	return config
}

main 函数入口调用

// 声明当前文件属于哪个包,如果是主文件,则写成main
package main

// 导入gin包
import (
	"fmt"
	"hello-gin/util/config"
)

func main() {
	confINI := config.LoadINIConfig("configs/config.ini")
	fmt.Println(confINI)
	fmt.Println("App : ", confINI.App)
	fmt.Println("Log : ", confINI.Log)
	fmt.Println("Database :", confINI.DbRedis.Database)
}

执行结果:

go run .\main.go
&{{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}}
App :  {hellogin dev localhost 8080 weiyigeek}
Log :  {D:/Study/Project/Go/hello-gin/logs ginDemo 180 100 24}
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 配置文件示例

app:
  name: "hellogin"
  mode: "dev"
  host: "localhost"
  port: "8080"
  secret: "weiyigeek"
log:
  name: "ginDemo"
  path: "D:/Study/Project/Go/hello-gin/logs"
  maxage: 180
  rotation_time: 24
  rotation_size: 100
db:
  mysql:
    host: 192.168.2.2
    port: 3306
    user: weiyigeek
    pass: 123456
    database: weiyigeek
  redis:
    host: 192.168.2.6
    port: 3306
    pass: weiyigeek.top
    database: 10
user:
  user:
  - weiyigeek
  - geeker
  
  mqtt:
    host: 192.168.2.7:1883
    username: weiyigeek
    password: weiyigeek.top

LoadYAMLConfig 函数读取yaml配置文件

package config

import (
	"fmt"
	"io/ioutil"
	"log"

	"gopkg.in/yaml.v3"
)

// 读取yaml配置文件
// YAML 配置文件结构体
type AppYAMLConfig struct {
	AppName   string `yaml:"name"`
	AppMode   string `yaml:"mode"`
	AppHost   string `yaml:"host"`
	AppPort   string `yaml:"port"`
	AppSecret string `yaml:"secret"`
}

type LogYAMLConfig struct {
	LogPath         string `yaml:"path"`
	LogName         string `yaml:"name"`
	LogAge          string `yaml:"age"`
	LogRotationTime string `yaml:"rotation_time"`
	LogRotationSize string `yaml:"rotation_size"`
}

type DbMySQLYAMLConfig struct {
	User     string `yaml:"user"`
	Pass     string `yaml:"pass"`
	Addr     string `yaml:"addr"`
	Port     string `yaml:"port"`
	Database string `yaml:"database"`
}
type DbRedisYAMLConfig struct {
	Addr     string `yaml:"addr"`
	Port     string `yaml:"port"`
	Pass     string `yaml:"pass"`
	Database string `yaml:"database"`
}
type DbYAMLConfig struct {
	Mysql DbMySQLYAMLConfig `yaml:"mysql"`
	Redis DbRedisYAMLConfig `yaml:"redis"`
}

type MqttYAMLconfig struct {
	Host     string `yaml:"host"`
	Username string `yaml:"username"`
	Password string `yaml:"password"`
}

type UserYAMLconfig struct {
	User []string       `yaml:"user"`
	Mqtt MqttYAMLconfig `yaml:"mqtt"`
}

type YAMLConfig struct {
	App  AppYAMLConfig  `yaml:"app"`
	Log  LogYAMLConfig  `yaml:"log"`
	Db   DbYAMLConfig   `yaml:"db"`
	User UserYAMLconfig `yaml:"user"`
}

func LoadYAMLConfig(path string) *YAMLConfig {
	// 定义局部变量
	config := &YAMLConfig{}

	// 打开并读取yaml配置文件
	yamlFile, err := ioutil.ReadFile(path)
	if err != nil {
		log.Printf("Open config.yaml failed!")
		panic(err)
	}

	// 使用yaml中Unmarshal方法,解析yaml配置文件并绑定定义的结构体
	err = yaml.Unmarshal(yamlFile, config)
	if err != nil {
		log.Printf("yaml config file Unmarsha failed!")
		panic(err)
	}

	return config
}

入口函数:

// 声明当前文件属于哪个包,如果是主文件,则写成main
package main

// 导入gin包
import (
	"fmt"
	"hello-gin/util/config"
)

func main() {
	confYAML := config.LoadYAMLConfig("configs/config.yaml")
	fmt.Print(confYAML, "\n")
	fmt.Println("--------------------------------------------------------------")
	fmt.Println("应用用户", confYAML.User.User)
	fmt.Println("应用名称", confYAML.App.AppName)
	fmt.Println("应用密钥", confYAML.App.AppSecret)
	fmt.Println("MySQL账号密码:", confYAML.Db.Mysql.User, confYAML.Db.Mysql.Pass)
}

执行结果:

&{{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}}}
--------------------------------------------------------------
应用用户 [weiyigeek geeker]
应用名称 hellogin
应用密钥 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


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

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


常规使用

// # 如果没有通过配置文件、环境变量、远程配置或命令行标志(flag)设置键,则默认值非常有用。
viper.SetDefault("ContentDir", "content")
viper.SetDefault("LayoutDir", "layouts")
viper.SetDefault("Taxonomies", map[string]string{"tag": "tags", "category": "categories"})

// # Viper支持JSON、TOML、YAML、HCL、envfile和Java properties格式的配置文件
// 方式1
viper.SetConfigFile("config.yaml")     // 指定配置文件路径
viper.AddConfigPath("/etc/appname/")   // 查找配置文件所在的路径

// 方式2
viper.SetConfigName("config")          // 配置文件名称(无扩展名)
viper.SetConfigType("yaml")            // 如果配置文件的名称中没有扩展名,则需要配置此项
viper.AddConfigPath("/etc/appname/")   // 查找配置文件所在的路径
viper.AddConfigPath("$HOME/.appname")  // 多次调用以添加多个搜索路径
viper.AddConfigPath(".")               // 还可以在工作目录中查找配置

// # 通过 ReadInConfig 函数,寻找配置文件并读取,操作的过程中可能会发生错误,如配置文件没找到,配置文件的内容格式不正确等;
if err := viper.ReadInConfig(); err != nil {
  if _, ok := err.(viper.ConfigFileNotFoundError); ok {
    // 配置文件未找到错误;如果需要可以忽略
  } else {
    // 配置文件被找到,但产生了另外的错误
  }
} else {
  // 配置文件找到并成功解析
}

// # Viper 覆盖设置
viper.Set("Verbose", true)
viper.Set("LogFile", LogFile)


// # 通过 ReadInConfig 函数,寻找配置文件并读取,操作的过程中可能会发生错误,如配置文件没找到,配置文件的内容格式不正确等;
fmt.Println(viper.Get("mysql"))     // map[port:3306 url:127.0.0.1]
fmt.Println(viper.Get("mysql.url")) // 127.0.0.1

// # 使用viper函数获取嵌套的键的值
{
  "host": {
    "address": "localhost",
    "port": 5799
  },
  "datastore": {
      "mysql": {
        "host": "127.0.0.1",
        "port": 3306
      }
  }
}

viper.GetString("datastore.mysql.host") // (返回 "127.0.0.1")

// # 获取子树值
app:
  cache1:
    max-items: 100
    item-size: 64
  cache2:
    max-items: 200
    item-size: 80

subv := viper.Sub("app.cache1")

// # viper加载完配置信息后使用结构体变量保存配置信息
type Config struct {
	Port    int    `mapstructure:"port"`
	Version string `mapstructure:"version"`
}
var Conf = new(Config)
// 将读取的配置信息保存至全局变量Conf
if err := viper.Unmarshal(Conf); err != nil {
  panic(fmt.Errorf("unmarshal conf failed, err:%s \n", err))
}

// # 使用WatchConfig监控配置文件变化
viper.WatchConfig()
// 注意!!!配置文件发生变化后要同步到全局变量Conf
viper.OnConfigChange(func(in fsnotify.Event) {
  fmt.Println("配置文件被修改了")
  if err := viper.Unmarshal(Conf); err != nil {
    panic(fmt.Errorf("unmarshal conf failed, err:%s \n", err))
  }
})

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

package main

import (
	"flag"
	"fmt"

	"github.com/spf13/pflag"
	"github.com/spf13/viper"
)

func main() {
	// 使用标准库 "flag" 包
	flag.Int("flagname", 1234, "help message for flagname")

	// pflag 包可以通过导入这些 flags 来处理flag包定义的flags, pflag 包可以通过导入这些 flags 来处理flag包定义的flags
	pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
	pflag.Parse()

	// viper 绑定到标志
	viper.BindPFlags(pflag.CommandLine)

	// 从 viper 检索值
	i := viper.GetInt("flagname")
	fmt.Println(i)  // 1234
}

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

configs\prod.yaml 配置文件

app:
  name: "hellogin"
  mode: "dev"
  host: "localhost"
  port: "8080"
  secret: "weiyigeek"
  version: "v1.2.0"
log:
  name: "ginDemo"
  path: "D:/Study/Project/Go/hello-gin/logs"
  maxage: 180
  rotation_time: 24
  rotation_size: 100
db:
  mysql:
    host: 192.168.2.2
    port: 3306
    user: weiyigeek
    pass: 123456
    database: weiyigeek
  redis:
    host: 192.168.2.6
    port: 3306
    pass: weiyigeek.top
    database: 10

代码示例:

// go get -v -u  gopkg.in/yaml.v3
package main

import (
	"fmt"
	"github.com/fsnotify/fsnotify"
	"github.com/spf13/viper"
)

// YAML 配置文件KV结构体
type AppYAMLConfig struct {
	AppName    string `mapstructure:"name"`
	AppMode    string `mapstructure:"mode"`
	AppHost    string `mapstructure:"host"`
	AppPort    string `mapstructure:"port"`
	AppSecret  string `mapstructure:"secret"`
	AppVersion string `mapstructure:"version"`
}

type LogYAMLConfig struct {
	LogPath         string `mapstructure:"path"`
	LogName         string `mapstructure:"name"`
	LogAge          string `mapstructure:"age"`
	LogRotationTime string `mapstructure:"rotation_time"`
	LogRotationSize string `mapstructure:"rotation_size"`
}

type DbMySQLYAMLConfig struct {
	User     string `mapstructure:"user"`
	Pass     string `mapstructure:"pass"`
	Addr     string `mapstructure:"addr"`
	Port     string `mapstructure:"port"`
	Database string `mapstructure:"database"`
}
type DbRedisYAMLConfig struct {
	Addr     string `mapstructure:"addr"`
	Port     string `mapstructure:"port"`
	Pass     string `mapstructure:"pass"`
	Database string `mapstructure:"database"`
}
type DbYAMLConfig struct {
	Mysql DbMySQLYAMLConfig `mapstructure:"mysql"`
	Redis DbRedisYAMLConfig `mapstructure:"redis"`
}

type MqttYAMLconfig struct {
	Host     string `mapstructure:"host"`
	Username string `mapstructure:"username"`
	Password string `mapstructure:"password"`
}

type YAMLConfig struct {
	App AppYAMLConfig `mapstructure:"app"`
	Log LogYAMLConfig `mapstructure:"log"`
	Db  DbYAMLConfig  `mapstructure:"db"`
}

// viper对象示例化与配置文件读取
func NewConfig(name string) *viper.Viper {
	// 设置实例化viper对象
	vp := viper.New()
	// 设置配置文件名,没有后缀
	vp.SetConfigName(name)
	// 设置读取文件格式为: yaml
	vp.SetConfigType("yaml")
	// 设置配置文件目录(可以设置多个,优先级根据添加顺序来)
	vp.AddConfigPath("./configs/")

	// 读取配置文件并解析
	if err := vp.ReadInConfig(); err != nil {
		if _, ok := err.(viper.ConfigFileNotFoundError); ok {
			fmt.Printf("配置文件未找到!%v\n", err)
			return nil
		} else {
			fmt.Printf("找到配置文件,但是解析错误,%v\n", err)
			return nil
		}
	}
	// 绑定返回结构体对象
	return vp
}

func main() {
	// 实例化 vp 对象
	vp := NewConfig("prod")

	// 获取指定key值
	fmt.Println("Version : ", vp.Get("app.version"))

	// 获取指定节值返回map数据类型
	fmt.Println(vp.GetStringMap("app"))
	v := vp.GetStringMap("app")
	fmt.Println("version : ", v["version"], "\n")

	// 将获取到的数据绑定到结构体
	conf := new(YAMLConfig)
	if err := vp.Unmarshal(conf); err != nil {
		fmt.Printf("解析错误: %v\n", err)
		panic(err)
	}
	fmt.Println(conf, "\n")

	// 监控配置文件的变化
	// # 使用WatchConfig监控配置文件变化
	vp.WatchConfig()
	// 注意!!!配置文件发生变化后要同步到全局变量Conf
	vp.OnConfigChange(func(in fsnotify.Event) {
		fmt.Println("配置文件被修改了")
		if err := vp.Unmarshal(conf); err != nil {
			panic(fmt.Errorf("unmarshal conf failed, err:%s \n", err))
		}
	})
	fmt.Println(vp)
}

执行结果:

go run .\main.go
Version :  v1.2.0
map[host:localhost mode:dev name:hellogin port:8080 secret:weiyigeek version:v1.2.0]
version :  v1.2.0

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

&{. [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 
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 配置文件

appName=hellogin
appMode=dev
appHost=localhost
appPort=8080
appSecret="WeiyiGeek"

logName="ginDemo"
logPath="D:/Study/Project/Go/hello-gin/logs"
logMaxage=180
logRotationTime=24
logRotationSize=100

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

632e101430f89c01015a7a5c77399174.jpeg

LoadPropConfig 函数读取properties配置文件

package config

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"strings"
)

var properties = make(map[string]string)

func LoadPropConfig(path string) map[string]string {
	propFile, err := os.OpenFile(path, os.O_RDONLY, 0666)
	if err != nil {
		fmt.Println("打开 config.properties 配置文件失败!")
		panic(err)
	}

	propReader := bufio.NewReader(propFile)
	for {
		prop, err := propReader.ReadString('\n')
		if err != nil {
			if err == io.EOF {
				break
			}
		}
		// 此处注意不要出现Yoda conditions问题
		if (len(prop) == 0) || (prop == "\n") {
			continue
		}
		properties[strings.Replace(strings.Split(prop, "=")[0], " ", "", -1)] = strings.Replace(strings.Split(prop, "=")[1], " ", "", -1)
	}

	return properties
}

函数调用主入口

// 声明当前文件属于哪个包,如果是主文件,则写成main
package main

// 导入gin包
import (
	"fmt"
	"hello-gin/util/config"
)

func main() {
	properties := config.LoadPropConfig("configs/config.properties")
	fmt.Println(properties)
	fmt.Print("AppName : ", properties["appName"])
	fmt.Println("LogPath : ", properties["logPath"])
}

执行结果:

$ go run .\main.go
map[appHost:localhost
 appMode:dev
 appName:hellogin
 appPort:8080
 appSecret:"WeiyiGeek"
 logMaxage:180
 logName:"ginDemo"
 logPath:"D:/Study/Project/Go/hello-gin/logs"
 logRotationTime:24
]
AppName : hellogin
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学习之路汇总】

 热文推荐  

  • 容灾恢复 | 记一次K8S集群中etcd数据快照的备份恢复实践

  • 企业实践 | 如何从VMWare ESXi Shell中挂载以及拷贝NTFS或者FAT32分区格式的USB闪存驱动器

  • 奇技淫巧 | 快速提升网站权重,巧用GPT4自动化大数据生成关键字指数进行SEO排名优化

  • 网安等保-国产Linux操作系统银河麒麟KylinOS-V10SP3常规配置、系统优化与安全加固基线实践文档

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

0b496bbc294b3d7e09fd9fa0a74b7d94.jpeg8aa0248ba3bacd66e6a3e8ad4162050e.jpegd6c953cc34e42fbcf72c1f8e0284cba9.jpeg

303fe77ff5fa78609659b7c25172b739.gif

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

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

微信沟通交流: weiyigeeker 

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

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

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

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

点个【 赞 + 在 】看吧!

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/592041.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

docker 数据持久化

目录 一、将本地目录直接映射到容器里&#xff08;运行成容器时候进行映射&#xff09; 二、数据卷模式 1、创建数据卷 2、查看数据卷列表&#xff0c;有哪些数据卷 3、查看某个数据卷 4、容器目录挂载到数据卷 5、数据卷的优势&#xff1a;多个容器共享一个数据卷 默认…

元宇宙应用领域-教育

教育是一个国家发展的基础&#xff0c;在科技发展的时代&#xff0c;元宇宙将会帮助教育行业实现跨越式发展。 元宇宙与教育的结合将会对传统的教学模式带来翻天覆地的变化。它能将线上教学、线下体验、远程互动等优势集于一身&#xff0c;也能把教师从繁重的重复劳动中解放出…

贝叶斯伪标签:鲁棒高效半监督分割的期望最大化

文章目录 Bayesian Pseudo Labels: Expectation Maximization for Robust and Efficient Semi-supervised Segmentation摘要作为期望最大化的伪标签基于变分推理的伪标签的推广实验结果 Bayesian Pseudo Labels: Expectation Maximization for Robust and Efficient Semi-super…

Qt上位机开发-学习记录(一)

一、Qt的安装 下载Qt : https://download.qt.io/ 进入archive/qt/&#xff0c;目前5.14版本下&#xff0c;有直接exe安装的版本&#xff0c;就直接下载 qt-opensource-windows-x86-5.14.2.exe安装Qt : 默认安装&#xff0c;过程中可以先全选 二、新建项目 选择Appliation-&g…

静态代码块、动态代码块、构造方法

类与对象 类&#xff1a;描述事物属性和行为 属性&#xff1a;私有化 行为&#xff1a;公开化 对象&#xff1a;就是类的一个具体实例 代码块&#xff1a; 静态代码块 发生在创建对象之前--时机 随着类的加载而加载 构造代码块 发生在创建对象之前&a…

解决小程序富文本显示视频问题

目录 1. 首先用小程序原生的 rich-text 肯定是不行的&#xff0c;它video的HTML节点和属性都不支持的 2. 采用安装插件的方法去处理&#xff08;强烈推荐&#xff1a;mp-html&#xff0c;可用于多端&#xff09; 3. 引入 4. 使用 5. 效果 1. 首先用小程序原生的 rich-text…

NLP实战:中文文本分类-Pytorch实现

目录 一、准备工作 1.任务说明 2.加载数据 二、数据预处理 1.构建词典 2.生成数据批次和迭代器 三、模型构建 1. 搭建模型 2.初始化模型 3. 定义训练与评估函数 四、训练模型 1. 拆分数据集并运行模型 顺便测试指定数据 五、总结 &#x1f368; 本文为[&#x1f517…

Benewake(北醒) 快速实现TF03-CAN与电脑通信操作说明

目录 一、前言二、工具准备三、连接方式3.1 串口通信连接方式3.2 CAN 通信连接方式 四、TF03 与电脑通信操作说明4.1 切换为CAN通信4.2 安装 USB_CAN TOOL 驱动4.3 CAN 通信下修改波特率 五、常见问题反馈5.1 V9.11 USB-CAN tool按照上述方案发送文件指令不成功的解决方案 一、…

跨平台开发的优势:ReactNative与小程序容器技术

结合React Native和小程序容器技术&#xff0c;开发者可以通过热重载和快速迭代提高开发效率&#xff0c;并实现统一的代码和逻辑&#xff0c;简化维护和升级过程。这种技术应用价值使得开发者能够更灵活地构建跨平台应用程序&#xff0c;并充分利用多个生态系统的优势。 Reac…

设计模式之~模板方法模式

定义&#xff1a; 定义一个操作中的算法的骨架&#xff0c;而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 &#xff08;算法的骨架&#xff0c;可以理解为你根据需求设计出来的业务流程&#xff1b; 特定的步骤就是指那…

Ubuntu 17.04 壁纸设计大赛 已经开幕

导读Ubuntu 团队成员 Nathan Haines 向外媒 Softpedia 知会了一场全新的“Free Culture Showcase”活动 —— 为即将到来的 Ubuntu 17.04&#xff08;Zesty Zapus&#xff09;操作系统征集壁纸。 需要指出的是&#xff0c;这场壁纸设计大赛并不会有任何奖励。但如果你的作品有…

驱动开发:内核解析PE结构导出表

在笔者的上一篇文章《驱动开发&#xff1a;内核特征码扫描PE代码段》中LyShark带大家通过封装好的LySharkToolsUtilKernelBase函数实现了动态获取内核模块基址&#xff0c;并通过ntimage.h头文件中提供的系列函数解析了指定内核模块的PE节表参数&#xff0c;本章将继续延申这个…

怎么将Windows操作系统从物理机迁移到虚拟机?

“我的服务器上安装了Windows Server 2003。我真的很想通过VMWare EXSi作为虚拟机运行它&#xff0c;但我不知道必须重新配置整个过程。有没有一种相对轻松的方式移动到虚拟机&#xff1f;它将保持在具有完全相同硬件的同一个盒子上......没有任何变化。” 像这个用户一样&…

书中隐藏的 SQL 开窗函数秘密,ChatGPT 找到了

平时写出这份 T-SQL 的开窗函数脚本&#xff0c;大多数开发者都会引以为傲了&#xff1a; SELECT empid, ordermonth, qty, SUM(qty) OVER (PARTITION BY empid ORDER BY ordermonth ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS run_sum_qty, AVG(qty) OVER (PARTIT…

当Windows里运行spark程序长时间不报错也不出结果(如何将scala程序打包放在虚拟机里运行)

当Windows里运行spark程序长时间不报错也不出结果 Windows内存不足也可能导致Spark程序长时间没有报错也没有输出结果的情况。Spark在处理大规模数据时需要大量的内存&#xff0c;如果可用内存不足&#xff0c;可能会导致程序运行缓慢或无法完成任务。 要确认内存是否是问题所…

80211(b/a/n/ac)速率介绍

80211&#xff08;b/a/n/ac&#xff09;速率介绍 1.第一代wifi标准 80211&#xff08;80211b&#xff09;&#xff08;2.4G&#xff09; 1997年完成&#xff0c;传输速率支持1Mbps 和 2Mbps。支持采用FHSS&#xff08;跳频&#xff09;和DSSS&#xff08;直接序列扩频&#x…

【工作流】Activiti工作流简介以及Spring Boot 集成 Activiti7

文章目录 前言一、activiti介绍二、工作流引擎三、BPMN四、数据库五、Spring Boot 集成 Activiti7安装插件引入依赖配置文件 总结 前言 什么是工作流&#xff1f; 工作流指通过计算机对业务流程进行自动化管理&#xff0c;实现多个参与者按照预定义的流程去自动执行业务流程。 …

冲击百万大奖!广州·琶洲算法大赛赛题讲解会,7场直播直击命题重点

‍‍第二届广州琶洲算法大赛是由广州市人民政府主办、海珠区人民政府和百度公司等单位联合承办的赛事&#xff0c;旨在为企业、高校师生、广大开发者提供展示技术能力、开展跨界交流、促进创业就业的平台。大赛自 4 月 25 日启动以来&#xff0c;吸引了超过 1000 支队伍报名参赛…

6.3 守护进程

目录 守护进程 守护进程特点 守护进程-相关概念 守护进程创建&#xff08;一&#xff09; 守护进程创建&#xff08;二&#xff09; 守护进程创建&#xff08;三&#xff09; 守护进程创建&#xff08;四&#xff09; 守护进程创建&#xff08;五&#xff09; 守护进程…

MS913,MS914,25-100MHz 10/12 位用于平面显示器链路Ⅲ的具有直流平衡编码和双向控制通道的串化器和解串器

MS913/MS914 芯片组是 25MHz~100MHz 10 位/12 位 FPD&#xff0c;Link III SER/DES(串化器/解串器)&#xff0c;它提供高速 FPD-Link III 接口和高速正向通路以及用于差分对上数据发送的双向 控制通路。广泛应用于车载摄像&#xff0c;医疗设备&#xff0c;管道探测等领域 MS91…