(Go) 如何使用 toml 文件?

9
作为标题,我想知道如何在golang中使用toml文件。
在此之前,请查看我的toml示例。这样对吗?
[datatitle]
enable = true
userids = [
    "12345", "67890"
]
    [datatitle.12345]
    prop1 = 30
    prop2 = 10

    [datatitle.67890]
    prop1 = 30
    prop2 = 10

然后,我想将这些数据设置为结构体类型。

因此,我希望能够按以下方式访问子元素。

datatitle["12345"].prop1
datatitle["67890"].prop2

提前感谢!


你尝试过什么吗? 给我们展示一些代码 :) - MIkCode
5
https://godoc.org/?q=toml - Volker
非常抱歉,说明不足。 - Harry
6个回答

11

首先获取BurntSushi的toml解析器:

go get github.com/BurntSushi/toml

BurntSushi将toml解析并映射到结构体,这正是您想要的。

然后执行以下示例并从中学习:

package main

import (
    "github.com/BurntSushi/toml"
    "log"
)

var tomlData = `title = "config"
[feature1]
enable = true
userids = [
  "12345", "67890"
]

[feature2]
enable = false`

type feature1 struct {
    Enable  bool
    Userids []string
}

type feature2 struct {
    Enable bool
}

type tomlConfig struct {
    Title string
    F1    feature1 `toml:"feature1"`
    F2    feature2 `toml:"feature2"`
}

func main() {
    var conf tomlConfig
    if _, err := toml.Decode(tomlData, &conf); err != nil {
        log.Fatal(err)
    }
    log.Printf("title: %s", conf.Title)
    log.Printf("Feature 1: %#v", conf.F1)
    log.Printf("Feature 2: %#v", conf.F2)
}

注意 tomlData 如何映射到 tomlConfig 结构体。

更多示例请参见 https://github.com/BurntSushi/toml


谢谢您的好建议!我会尝试并向您反馈! - Harry
1
@Harry,我修复了这个例子,它之前运行得不太好。据我所见,BurnSushi/toml库不支持在类别中使用点号,就像你的问题所展示的那样。如果你一定要使用这些点号,可以尝试另一个库,比如https://github.com/pelletier/go-toml。 - Zippo
1
非常感谢您的帮助!我会在有空的时候反馈我的代码。非常感谢! - Harry
@Harry 很高兴我能帮到你,欢迎来到 Stack Overflow :-). 如果这个答案解决了你的问题,请将其标记为已接受。 - Zippo
1
你好。很抱歉告诉您,BurntSushi/toml已经正式停止维护了。https://github.com/BurntSushi/toml/commit/ea60c4def909bde529d41a7e0674e31eba751da3 - Felixoid

5

2019年的一个小更新 - 现在有一个比 BurntSushi/toml 更好的替代品,API更丰富,可用于处理 .toml 文件:

pelletier/go-toml (以及文档)

例如,有一个config.toml文件(或者在内存中):

[postgres]
user = "pelletier"
password = "mypassword"

除了常规的将整个内容解组和编组成预定义结构(您可以在被接受的答案中看到)之外,使用pelletier/go-toml,您还可以像这样查询单个值:
config, err := toml.LoadFile("config.toml")

if err != nil {
    fmt.Println("Error ", err.Error())
} else {

    // retrieve data directly

    directUser := config.Get("postgres.user").(string)
    directPassword := config.Get("postgres.password").(string)
    fmt.Println("User is", directUser, " and password is", directPassword)

    // or using an intermediate object

    configTree := config.Get("postgres").(*toml.Tree)
    user := configTree.Get("user").(string)
    password := configTree.Get("password").(string)
    fmt.Println("User is", user, " and password is", password)

    // show where elements are in the file

    fmt.Printf("User position: %v\n", configTree.GetPosition("user"))
    fmt.Printf("Password position: %v\n", configTree.GetPosition("password"))

    // use a query to gather elements without walking the tree

    q, _ := query.Compile("$..[user,password]")
    results := q.Execute(config)
    for ii, item := range results.Values() {
        fmt.Println("Query result %d: %v", ii, item)
    }
}

更新

还有spf13/viper,它可以使用.toml配置文件(以及其他支持的格式),但在许多情况下可能有些过度。

更新2

Viper并不是一个真正的替代方案(感谢@GoForth)。


1
实际上,Viper使用Pelletier的库:https://github.com/spf13/viper/blob/master/viper.go#L43 - GoForth
1
@GoForth,这很好知道,谢谢!我想我们可以从问题中划掉viper :) - Sevenate
1
当我深入了解它时,我也感到惊讶。尽管如此,我仍然认为 Viper 很酷,因为它是一个多合一的解决方案。但我想指出,如果有人只是寻找 TOML,那么这个东西会更适合他们。 - GoForth

3
这个问题已经通过使用推荐的包BurntSushi/toml得到解决!我按照以下方式进行了操作,这是代码的一部分。
[toml示例]
[title]
enable = true
[title.clientinfo.12345]
distance = 30
some_id = 6

[Golang 示例]
type TitleClientInfo struct {
    Distance int    `toml:"distance"`
    SomeId  int     `toml:"some_id"`
}

type Config struct {
    Enable     bool     `toml:"enable"`
    ClientInfo map[string]TitleClientInfo `toml:"clientinfo"`
}

var config Config
_, err := toml.Decode(string(d), &config)

然后,它可以按照我的预期使用。

config.ClientInfo[12345].Distance

谢谢!


2

使用解决方案Viper,您可以使用JSON、TOML、YAML、HCL、INI和其他属性格式的配置文件。

创建文件:

./config.toml

首先导入:

import (config "github.com/spf13/viper")

初始化:
config.SetConfigName("config")
config.AddConfigPath(".")
err := config.ReadInConfig()
if err != nil {             
    log.Println("ERROR", err.Error())
}

获取该值:

config.GetString("datatitle.12345.prop1")
config.Get("datatitle.12345.prop1").(int32)

文档:https://github.com/spf13/viper

例如:https://repl.it/@DarlanD/Viper-Examples#main.go


0

我正在使用spf13/viper

第三方包

状态 项目 开始时间 分支数
活动的 spf13/viper stars stars
活动的 BurntSushi/toml stars stars

viper 的使用

我尝试使用表格将代码和配置文件内容放在一起,但显然编辑与最终结果不匹配,因此我将图片上传,希望这样可以更容易地进行比较。

enter image description here


package main
import (
    "github.com/spf13/viper"
    "log"
    "os"
)
func main() {
    check := func(err error) {
        if err != nil {
            panic(err)
        }
    }
    myConfigPath := "test_config.toml"
    fh, err := os.OpenFile(myConfigPath, os.O_RDWR, 0666)
    check(err)
    viper.SetConfigType("toml") // do not ignore
    err = viper.ReadConfig(fh)
    check(err)

    // Read
    log.Printf("%#v", viper.GetString("title"))                 // "my config"
    log.Printf("%#v", viper.GetString("DataTitle.12345.prop1")) // "30"
    log.Printf("%#v", viper.GetString("dataTitle.12345.prop1")) // "30"  // case-insensitive
    log.Printf("%#v", viper.GetInt("DataTitle.12345.prop1"))    // 30
    log.Printf("%#v", viper.GetIntSlice("feature1.userids"))    // []int{456, 789}

    // Write
    viper.Set("database", "newuser")
    viper.Set("owner.name", "Carson")
    viper.Set("feature1.userids", []int{111, 222}) // overwrite
    err = viper.WriteConfigAs(myConfigPath)
    check(err)
}
title = "my config"

[datatitle]

  [datatitle.12345]
    prop1 = 30

[feature1]
  userids = [456,789]

database = "newuser"  # New
title = "my config"

[datatitle]

  [datatitle.12345]
    prop1 = 30

[feature1]
  userids = [111,222]  # Update

[owner]  # New
  name = "Carson"


1
BurntSushi/toml 最近有了新的维护者 https://github.com/BurntSushi/toml/issues/272 它不再是未维护的了。 - user4466350
1
嗨,@mh-cbon,谢谢你的提醒。[Unmaintained is create on 2020-10-18 by Andrew Gallant](https://github.com/BurntSushi/toml/blob/ea60c4def909bde529d41a7e0674e31eba751da3/README.md)。它已经被Martin Tournoij于2021-06-08移除 - Carson

0

1
请在您的回答中提供更多细节。目前的写法很难理解您的解决方案。 - Community

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