英文:
(Go) How to use toml files?
问题
标题上写着,我想知道如何在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
提前感谢!
英文:
As title, I want to know how to use toml files from golang.
Before that, I show my toml examples. Is it right?
[datatitle]
enable = true
userids = [
"12345", "67890"
]
[datatitle.12345]
prop1 = 30
prop2 = 10
[datatitle.67890]
prop1 = 30
prop2 = 10
And then, I want to set these data as type of struct.
As a result I want to access child element as below.
datatitle["12345"].prop1
datatitle["67890"].prop2
Thanks in advance!
答案1
得分: 10
首先获取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上查看更多示例。
英文:
First get BurntSushi's toml parser:
go get github.com/BurntSushi/toml
BurntSushi parses toml and maps it to structs, which is what you want.
Then execute the following example and learn from it:
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)
}
Notice the tomlData
and how it maps to the tomlConfig
struct.
See more examples at https://github.com/BurntSushi/toml
答案2
得分: 4
2019年的一个小更新 - 现在有一个比BurntSushi/toml更新的替代品,它具有更丰富的API来处理**.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 {
// 直接获取数据
directUser := config.Get("postgres.user").(string)
directPassword := config.Get("postgres.password").(string)
fmt.Println("User is", directUser, " and password is", directPassword)
// 或者使用中间对象
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)
// 显示元素在文件中的位置
fmt.Printf("User position: %v\n", configTree.GetPosition("user"))
fmt.Printf("Password position: %v\n", configTree.GetPosition("password"))
// 使用查询来收集元素,而无需遍历树
q, _ := query.Compile("$..[user,password]")
results := q.Execute(config)
for ii, item := range results.Values() {
fmt.Println("Query result %d: %v", ii, item)
}
}
更新
<s>还有spf13/viper,它可以处理.toml配置文件(以及其他支持的格式),但在许多情况下可能有点过度设计。</s>
更新2
英文:
A small update for the year 2019 - there is now newer alternative to BurntSushi/toml with a bit richer API to work with .toml files:
pelletier/go-toml (and documentation)
For example having config.toml
file (or in memory):
[postgres]
user = "pelletier"
password = "mypassword"
apart from regular marshal and unmarshal of the entire thing into predefined structure (which you can see in the accepted answer) with pelletier/go-toml you can also query individual values like this:
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)
}
}
UPDATE
<s>There is also spf13/viper that works with .toml config files (among other supported formats), but it might be a bit overkill in many cases.</s>
UPDATE 2
Viper is not really an alternative (credits to @GoForth).
答案3
得分: 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
谢谢!
英文:
This issue was solved using recommended pkg BurntSushi/toml!!
I did as below and it's part of code.
[toml example]
[title]
enable = true
[title.clientinfo.12345]
distance = 30
some_id = 6
[Golang example]
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)
And then, it can be used as I expected.
config.ClientInfo[12345].Distance
Thanks!
答案4
得分: 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
英文:
With solution Viper you can use a configuration file in JSON, TOML, YAML, HCL, INI and others properties formats.
Create file:
./config.toml
First import:
import (config "github.com/spf13/viper")
Initialize:
config.SetConfigName("config")
config.AddConfigPath(".")
err := config.ReadInConfig()
if err != nil {
log.Println("ERROR", err.Error())
}
And get the value:
config.GetString("datatitle.12345.prop1")
config.Get("datatitle.12345.prop1").(int32)
答案5
得分: 0
我正在使用spf13/viper。
第三方包
状态 | 项目 | Stars | Forks |
---|---|---|---|
存活 | spf13/viper | ||
存活 | BurntSushi/toml |
viper的用法
我尝试使用表格将代码和配置文件的内容放在一起,但显然,编辑与最终结果不匹配,所以我将图片放在上面,希望这样更容易比较。
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") // 不要忽略
err = viper.ReadConfig(fh)
check(err)
// 读取
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" // 不区分大小写
log.Printf("%#v", viper.GetInt("DataTitle.12345.prop1")) // 30
log.Printf("%#v", viper.GetIntSlice("feature1.userids")) // []int{456, 789}
// 写入
viper.Set("database", "newuser")
viper.Set("owner.name", "Carson")
viper.Set("feature1.userids", []int{111, 222}) // 覆盖
err = viper.WriteConfigAs(myConfigPath)
check(err)
}
<div class="s-table-container">
<table class="s-table">
<thead>
<tr>
<th>(写入前)<br>test_config.toml</th>
<th>(写入后)<br>test_config.toml</th>
</tr>
</thead>
<tbody>
<tr>
<td>
title = "my config"
[datatitle]
[datatitle.12345]
prop1 = 30
[feature1]
userids = [456,789]
</td>
<td>
database = "newuser" # 新增
title = "my config"
[datatitle]
[datatitle.12345]
prop1 = 30
[feature1]
userids = [111,222] # 更新
[owner] # 新增
name = "Carson"
</td>
</tr>
</tbody>
</table>
</div>
英文:
I am using spf13/viper
3rd packages
Status | Project | Starts | Forks |
---|---|---|---|
Alive | spf13/viper | ||
Alive | BurntSushi/toml |
usage of viper
I tried to use a table to put the code and the contents of the configuration file together, but obviously, the editing did not match the final result, so I put the image up in the hope that it would make it easier for you to compare
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)
}
<div class="s-table-container">
<table class="s-table">
<thead>
<tr>
<th>(Write Before)<br>test_config.toml</th>
<th>(After)<br>test_config.toml</th>
</tr>
</thead>
<tbody>
<tr>
<td>
title = "my config"
[datatitle]
[datatitle.12345]
prop1 = 30
[feature1]
userids = [456,789]
</td>
<td>
database = "newuser" # New
title = "my config"
[datatitle]
[datatitle.12345]
prop1 = 30
[feature1]
userids = [111,222] # Update
[owner] # New
name = "Carson"
</td>
</tr>
</tbody>
</table>
</div>
答案6
得分: 0
我正在使用这个1 go-toml库。
它非常适合我的需求。我使用go-toml编写了这个2 go工具来处理containerd的config.toml文件。
1https://github.com/pelletier/go-toml
2https://github.com/prakashmirji/toml-configer
英文:
I am using this 1 go-toml library.
It works great for my uses. I wrote this 2 go util to deal with containerd config.toml file using go-toml
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论