Golang如何读取/生成yaml文件|Go主题月前言如

前言

在GO语言的常用领域---容器领域,我们经常使用yaml文件的形式来定义各种资源对象。也因此,k8s工程师也被戏称为yaml工程师。但是在日常使用中,我们对yaml文件的处理一般都是读取yaml文件,获取yaml文件中的配置。但是,如果我们需要通过代码中生成一个yaml文件应该怎么办呢?本文将通过"github.com/spf13/viper"包来实现该功能

如何读取yaml文件

在讲如何生成之前我们先讲一下如何读取yaml文件,有经验的同学可以直接跳到下一章

orgname: baas
channelname: publicchain
peer:
  - peer-0-baas
  - peer-1-baas
orderer:
  baas:
    - ServerHostName: orderer-0-baas:7050
      Address: 192.168.9.159:30004
    - ServerHostName: orderer-1-baas:7050
      Address: 192.168.9.159:30005
    - ServerHostName: orderer-2-baas:7050
      Address: 192.168.9.159:30006
  baas2:
    - ServerHostName: orderer-0-baas2:7050
      Address: 192.168.9.166:30012
复制代码

上面是一个简单的项目中的yaml配置文件,应该如何使用Golang读取该配置信息呢?

全量读取

type ConfigStruct struct {
    OrgName       string                   `yaml:"orgname"`
    ChannelName   string                   `yaml:"channelname"`
    Peer          []string                 `yaml:"peer"`
    Orderer       map[string][]OrdererInfo `yaml:"ORDERER"`
}

type OrdererInfo struct {
    ServerHostName string `yaml:"ServerHostName"`
    Address        string `yaml:"Address"`
}
复制代码

首先我们得定义一个与配置对应得结构体,如上所示,yaml中有四种特殊的tag标签

标签名 用途
omitempty 如果值为空则忽略掉该字段。还可以为该字段对应对结构体实现IsZero()接口,如果对应结构体实现了该接口,那么会按照接口返回值来确定是否忽略该字段
flow 这个标签用来表示你想使用流模式而非块模式
inline 内嵌类型
- 永远忽略该字段

然后,我们通过viper去读取该文件

var configViperConfig = viper.New()
configViperConfig.SetConfigName("config")
configViperConfig.SetConfigType("yaml")
//读取配置文件内容
if err = configViperConfig.ReadInConfig(); err != nil {
        panic(err)
}
var c ConfigStruct
if err = configViperConfig.Unmarshal(&c); err != nil {
        panic(err)
}
复制代码

这样,我们就可以在代码中通过c变量获取到配置信息

单点读取

如果我们只需要配置信息中到某个配置,也可以读取单个配置

var configViperConfig = viper.New()
configViperConfig.SetConfigName("config")
configViperConfig.SetConfigType("yaml")
//读取配置文件内容
if err = configViperConfig.ReadInConfig(); err != nil {
        panic(err)
}
复制代码

此时,我们通过viper包提供到Get方法

orgname := configViperConfig.Get("orgname")
复制代码

或者通过GetString方法

orgname := configViperConfig.GetString("orgname")
复制代码

如何写入配置文件

通过代码生成一个yaml文件也有两种方法,与上面读取一一对应

结构体生成yaml文件

通过创建一个对应的结构体,然后给对应字段复制后执行Marshal

type Conf struct {
    Test []string `yaml:"array.test,flow"`
}

func main(){
    data := `array.test: ["val1", "val2", "val3"]`
    var conf Conf
    yaml.Unmarshal([]byte(data), &conf)

    data2, _ := yaml.Marshal(conf)
    fmt.Printf("%s\n", string(data2))
}
复制代码

上边我们在读取yaml文件的时候,使用了Viper包的Get方法,既然有Get,那么自然就有Set

configViper := viper.New()
configViper.Set("version", "1.0.0")
// ......
c := configViper.AllSettings()
bytes, err := yaml.Marshal(c)
if err != nil {
        return nil, err
}
fmt.Println(string(bytes))
复制代码

Set方法的第一个传参是string类型的key,第二个传参是interface类型的value,所以如果结构比较复杂的话,可以将复杂部分的结构写成结构体Set到key中,但是需要主要该结构体的字段必须是可导出的,不然无法被viper调用,也就没法Marshal成功。