如何读取一个YAML文件

80

我在读取一个YAML文件时遇到了问题。我认为问题出现在文件结构上,但我无法找出原因。

YAML文件:

conf:
  hits:5
  time:5000000

代码:

type conf struct {
    hits int64 `yaml:"hits"`
    time int64 `yaml:"time"`
}


func (c *conf) getConf() *conf {

    yamlFile, err := ioutil.ReadFile("conf.yaml")
    if err != nil {
        log.Printf("yamlFile.Get err   #%v ", err)
    }
    err = yaml.Unmarshal(yamlFile, c)
    if err != nil {
        log.Fatalf("Unmarshal: %v", err)
    }

    return c
}

1
你看到了什么错误? - Amit Kumar Gupta
@AmitKumarGupta 我没有收到任何错误,只是一个空结构体。 - MIkCode
你觉得这些信息是否与你的问题相关?另外,你能否粘贴完整的代码以重现问题?包括package main、导入的文件、main函数等等,这样其他人就可以轻松地复制粘贴代码并在本地运行。请考虑添加信息和代码,使人们更容易帮助你,因为你需要他人的帮助。 - Amit Kumar Gupta
4
如前所述,使用反射方式(例如JSON、XML、YAML解包等)设置字段时,只能操作已导出的字段。翻译完成,没有其他内容返回。 - Dave C
5个回答

110

你的 YAML 文件必须是:

hits: 5
time: 5000000

你的代码应该像这样:

package main

import (
    "fmt"
    "gopkg.in/yaml.v2"
    "io/ioutil"
    "log"
)

type conf struct {
    Hits int64 `yaml:"hits"`
    Time int64 `yaml:"time"`
}

func (c *conf) getConf() *conf {

    yamlFile, err := ioutil.ReadFile("conf.yaml")
    if err != nil {
        log.Printf("yamlFile.Get err   #%v ", err)
    }
    err = yaml.Unmarshal(yamlFile, c)
    if err != nil {
        log.Fatalf("Unmarshal: %v", err)
    }

    return c
}

func main() {
    var c conf
    c.getConf()

    fmt.Println(c)
}

主要错误是你的结构体的首字母大写了。


1
导出标识符的规范:http://golang.org/doc/go_spec.html#Exported_identifiers - elithrar
2
这对我不起作用。我需要将err = yaml.Unmarshal(yamlFile,c)这一行更改为err = yaml.Unmarshal(yamlFile,&c)即传递指针而非值。但我不知道原因。 - förschter
它通过类型conf struct与代码绑定。如果配置文件更改,则无法重复使用。有没有什么是动态的,不需要在代码中定义一个结构体? - Mopparthy Ravindranath
2
@joelfischerr,你说得完全正确,我也不得不做出相同的更改才能使其正常工作。 - fabulias
如果您在不使用指针引用时遇到unmarshall错误,则原因是指针未定义或为空。在两种情况下,unmarshall需要地址:如果它是值类型或空指针类型。@fabulias和förschter - coder
显示剩余3条评论

23

示例

使用升级后的 版本 3 的 yaml 包。

一个示例的 conf.yaml 文件:

conf:
  hits: 5
  time: 5000000
  camelCase: sometext

main.go文件:

package main

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

    "gopkg.in/yaml.v3"
)

type myData struct {
    Conf struct {
        Hits      int64
        Time      int64
        CamelCase string `yaml:"camelCase"`
    }
}

func readConf(filename string) (*myData, error) {
    buf, err := ioutil.ReadFile(filename)
    if err != nil {
        return nil, err
    }

    c := &myData{}
    err = yaml.Unmarshal(buf, c)
    if err != nil {
        return nil, fmt.Errorf("in file %q: %w", filename, err)
    }

    return c, err
}

func main() {
    c, err := readConf("conf.yaml")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("%#v", c)
}

运行指南(如果这是您第一次离开 stdlib):

cat conf.yaml
go mod init example.com/whatever
go get gopkg.in/yaml.v3
cat go.sum
go run .

关于yaml:"field"

在所有小写的 YAML 键标识符中,标签(如 yaml:"field")都是可选的。以上示例演示了解析额外的驼峰命名标识符,需要使用此类标签。

特殊情况:JSON+YAML

令人困惑的是,yaml 包有用的小写行为在标准的 json 包中并没有体现出来。您是否有一种数据结构,有时编码为 JSON,有时编码为 YAML?如果是这样,请考虑在每个字段上指定 JSON 标签和 YAML 标签。虽然冗长,但可以减少错误。下面是一个示例:

type myData struct {
    Conf conf `yaml:"conf" json:"conf"`
}

type conf struct {
    Hits      int64  `yaml:"hits" json:"hits"`
    Time      int64  `yaml:"time" json:"time"`
    CamelCase string `yaml:"camelCase" json:"camelCase"`
}

2
package main

import (
    "gopkg.in/yaml.v2"
    "io/ioutil"
    "log"
)

type someConf struct {
    AccessKeyID     string `yaml:"access_key_id"`
   //...
}

func getConf(file string, cnf interface{}) error {
   yamlFile, err := ioutil.ReadFile(file)
   if err == nil {
      err = yaml.Unmarshal(yamlFile, cnf)
   }
   return err
}

func main() {
    cfg := &awsConf{}
    if err := getConf("conf.yml", cfg); err != nil {
        log.Panicln(err)
    }
 }

史上最短的getConf


0

在这里,您可以无需预定义的结构读取一个 YAML 文件。请将 "config.yaml" 替换为所需的文件名。将 "fmt,"、"io/ioutil," 和 "gopkg.in/yaml.v2" 添加到导入列表中。

    package main

    import (
        "fmt"
        "io/ioutil"

        "gopkg.in/yaml.v2"
    )

    func main() {
        obj := make(map[string]interface{})
    
        yamlFile, err := ioutil.ReadFile("config.yaml")
        if err != nil {
          fmt.Printf("yamlFile.Get err #%v ", err)
        }
        err = yaml.Unmarshal(yamlFile, obj)
        if err != nil {
          fmt.Printf("Unmarshal: %v", err)
        }

        fmt.Println(obj)
    }

0
这是在Golang中读取Yaml的更新版本。
file, err := os.OpenFile("config.yaml", os.O_RDONLY, 0600)

if err != nil {
    log.Fatalf("error opening/creating file: %v", err)
}
defer file.Close()

dec := yaml.NewDecoder(file)
err = dec.Decode(&Config)
if err != nil {
    err = fmt.Errorf("error loading config file %v!", err)
}else{
    pp.Print(Config)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接