320

我是 Go 编程的新手,我想知道:处理 Go 程序的配置参数的首选方法是什么(在其他情况下,可能使用属性文件或ini文件的那种东西)?

4

13 回答 13

264

JSON格式非常适合我。标准库提供了编写缩进数据结构的方法,因此可读性很强。

另请参阅此 golang-nuts 线程

JSON 的好处是解析和人类可读/可编辑相当简单,同时为列表和映射提供语义(这可以变得非常方便),而许多 ini 类型的配置解析器并非如此。

示例用法:

conf.json

{
    "Users": ["UserA","UserB"],
    "Groups": ["GroupA"]
}

读取配置的程序

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

type Configuration struct {
    Users    []string
    Groups   []string
}

file, _ := os.Open("conf.json")
defer file.Close()
decoder := json.NewDecoder(file)
configuration := Configuration{}
err := decoder.Decode(&configuration)
if err != nil {
  fmt.Println("error:", err)
}
fmt.Println(configuration.Users) // output: [UserA, UserB]
于 2013-05-09T16:05:58.917 回答
106

另一种选择是使用TOML,这是一种由 Tom Preston-Werner 创建的类似 INI 的格式。我为它构建了一个经过广泛测试的 Go 解析器。您可以像这里提出的其他选项一样使用它。例如,如果你有这个 TOML 数据something.toml

Age = 198
Cats = [ "Cauchy", "Plato" ]
Pi = 3.14
Perfection = [ 6, 28, 496, 8128 ]
DOB = 1987-07-05T05:45:00Z

然后你可以用类似的东西把它加载到你的 Go 程序中

type Config struct {
    Age int
    Cats []string
    Pi float64
    Perfection []int
    DOB time.Time
}

var conf Config
if _, err := toml.DecodeFile("something.toml", &conf); err != nil {
    // handle error
}
于 2013-05-10T22:01:49.250 回答
60

Viper是一个使用 JSON、YAML 和 TOML 的 golang 配置管理系统。它看起来很有趣。

于 2014-12-26T13:53:40.410 回答
48

我通常将 JSON 用于更复杂的数据结构。缺点是你很容易得到一堆代码来告诉用户错误在哪里,各种边缘情况以及什么不是。

对于基本配置(api 密钥、端口号、...),我对gcfg包非常幸运。它基于 git config 格式。

从文档中:

示例配置:

; Comment line
[section]
name = value # Another comment
flag # implicit value for bool is true

去结构:

type Config struct {
    Section struct {
            Name string
            Flag bool
    }
}

阅读它所需的代码:

var cfg Config
err := gcfg.ReadFileInto(&cfg, "myconfig.gcfg")

它还支持切片值,因此您可以允许多次指定一个键和其他类似的好功能。

于 2013-05-09T16:38:31.113 回答
44

只需使用带有iniflags的标准go 标志

去标志

import "flag"
var nFlag = flag.Int("n", 1234, "help message for flag n")

标志

package main

import (
  "flag"
  ...
  "github.com/vharitonsky/iniflags"
  ...
)

var (
  flag1 = flag.String("flag1", "default1", "Description1")
  ...
  flagN = flag.Int("flagN", 123, "DescriptionN")
)

func main() {
  iniflags.Parse()  // use instead of flag.Parse()
}

标准 go 标志有以下好处:

  • 惯用语。
  • 便于使用。标志可以很容易地添加和分散在项目使用的任意包中。
  • 标志对默认值和描述具有开箱即用的支持。
  • 标志提供带有默认值和描述的标准“帮助”输出。

标准 go 标志的唯一缺点 - 当您的应用程序中使用的标志数量变得太大时会出现管理问题。

Iniflags 优雅地解决了这个问题:只需修改主包中的两行,它就神奇地获得了从 ini 文件中读取标志值的支持。可以通过在命令行中传递新值来覆盖 ini 文件中的标志。

有关详细信息,另请参阅https://groups.google.com/forum/#!topic/golang-nuts/TByzyPgoAQE

于 2014-08-15T09:32:47.533 回答
13

我已经开始使用使用类似 Ini 文件的Gcfg 。这很简单——如果你想要一些简单的东西,这是一个不错的选择。

这是我当前使用的加载代码,它具有默认设置并允许覆盖我的一些配置的命令行标志(未显示):

package util

import (
    "code.google.com/p/gcfg"
)

type Config struct {
    Port int
    Verbose bool
    AccessLog string
    ErrorLog string
    DbDriver string
    DbConnection string
    DbTblPrefix string
}

type configFile struct {
    Server Config
}

const defaultConfig = `
    [server]
    port = 8000
    verbose = false
    accessLog = -
    errorLog  = -
    dbDriver     = mysql
    dbConnection = testuser:TestPasswd9@/test
    dbTblPrefix  =
`

func LoadConfiguration(cfgFile string, port int, verbose bool) Config {
    var err error
    var cfg configFile

    if cfgFile != "" {
        err = gcfg.ReadFileInto(&cfg, cfgFile)
    } else {
        err = gcfg.ReadStringInto(&cfg, defaultConfig)
    }

    PanicOnError(err)

    if port != 0 {
        cfg.Server.Port = port
    }
    if verbose {
        cfg.Server.Verbose = true
    }

    return cfg.Server
}
于 2013-05-10T09:02:43.960 回答
10

看看gonfig

// load
config, _ := gonfig.FromJson(myJsonFile)
// read with defaults
host, _ := config.GetString("service/host", "localhost")
port, _ := config.GetInt("service/port", 80)
test, _ := config.GetBool("service/testing", false)
rate, _ := config.GetFloat("service/rate", 0.0)
// parse section into target structure
config.GetAs("service/template", &template)
于 2015-11-16T05:35:09.010 回答
9

https://github.com/spf13/viperhttps://github.com/zpatrick/go-config是非常好的配置文件库。

于 2015-11-16T21:30:26.843 回答
7

像这篇文章一样使用toml Read config files the Go way

于 2015-10-29T10:00:10.870 回答
5

我在 golang 中编写了一个简单的 ini 配置库。

https://github.com/c4pt0r/cfg

goroutine 安全,易于使用

package cfg
import (
    "testing"
)

func TestCfg(t *testing.T) {
    c := NewCfg("test.ini")
    if err := c.Load() ; err != nil {
        t.Error(err)
    }
    c.WriteInt("hello", 42)
    c.WriteString("hello1", "World")

    v, err := c.ReadInt("hello", 0)
    if err != nil || v != 42 {
        t.Error(err)
    }

    v1, err := c.ReadString("hello1", "")
    if err != nil || v1 != "World" {
        t.Error(err)
    }

    if err := c.Save(); err != nil {
        t.Error(err)
    }
}

===================更新=======================

最近我需要一个支持section的INI解析器,我写了一个简单的包:

github.com/c4pt0r/cfg

你可以像使用“flag”包一样解析INI:

package main

import (
    "log"
    "github.com/c4pt0r/ini"
)

var conf = ini.NewConf("test.ini")

var (
    v1 = conf.String("section1", "field1", "v1")
    v2 = conf.Int("section1", "field2", 0)
)

func main() {
    conf.Parse()

    log.Println(*v1, *v2)
}
于 2014-05-07T07:48:17.917 回答
4

您可能还对go-libucl感兴趣,它是通用配置语言 UCL 的一组 Go 绑定。UCL 有点像 JSON,但对人类有更好的支持:它支持注释和人类可读的结构,如 SI 乘数(10k、40M 等),并且样板文件少一些(例如,键周围的引号)。如果您已经熟悉它,它实际上非常接近 nginx 配置文件格式。

于 2015-05-05T03:03:13.913 回答
2

我同意nemo的观点,我写了一个小工具来让这一切变得简单。

bitbucket.org/gotamer/cfg是一个 json 配置包

  • 您将应用程序中的配置项定义为结构。
  • 结构中的 json 配置文件模板在第一次运行时保存
  • 您可以将运行时修改保存到配置

有关示例,请参见 doc.go

于 2013-12-27T02:07:03.903 回答
1

我试过 JSON。有效。但我讨厌必须创建我可能设置的确切字段和类型的结构。对我来说那是一种痛苦。我注意到这是我能找到的所有配置选项使用的方法。也许我在动态语言方面的背景让我对这种冗长的好处视而不见。我制作了一个新的简单配置文件格式,以及一个更动态的库来读取它。

https://github.com/chrisftw/ezconf

我对 Go 世界很陌生,所以它可能不是 Go 方式。但它有效,它非常快,而且使用起来超级简单。

优点

  • 超级简单
  • 更少的代码

缺点

  • 没有数组或地图类型
  • 非常扁平的文件格式
  • 非标准配置文件
  • 确实有一些内置的约定,如果我现在在 Go 社区中普遍不赞成的话。(在 config 目录中查找配置文件)
于 2015-08-27T16:12:21.747 回答