操作键值(Value)

获取一个类型为字符串(string)的值:

  1. val := cfg.Section("").Key("key name").String()

获取值的同时通过自定义函数进行处理验证:

  1. val := cfg.Section("").Key("key name").Validate(func(in string) string {
  2. if len(in) == 0 {
  3. return "default"
  4. }
  5. return in
  6. })

如果您不需要任何对值的自动转变功能(例如递归读取),可以直接获取原值(这种方式性能最佳):

  1. val := cfg.Section("").Key("key name").Value()

判断某个原值是否存在:

  1. yes := cfg.Section("").HasValue("test value")

获取其它类型的值:

  1. // 布尔值的规则:
  2. // true 当值为:1, t, T, TRUE, true, True, YES, yes, Yes, y, ON, on, On
  3. // false 当值为:0, f, F, FALSE, false, False, NO, no, No, n, OFF, off, Off
  4. v, err = cfg.Section("").Key("BOOL").Bool()
  5. v, err = cfg.Section("").Key("FLOAT64").Float64()
  6. v, err = cfg.Section("").Key("INT").Int()
  7. v, err = cfg.Section("").Key("INT64").Int64()
  8. v, err = cfg.Section("").Key("UINT").Uint()
  9. v, err = cfg.Section("").Key("UINT64").Uint64()
  10. v, err = cfg.Section("").Key("TIME").TimeFormat(time.RFC3339)
  11. v, err = cfg.Section("").Key("TIME").Time() // RFC3339
  12. v = cfg.Section("").Key("BOOL").MustBool()
  13. v = cfg.Section("").Key("FLOAT64").MustFloat64()
  14. v = cfg.Section("").Key("INT").MustInt()
  15. v = cfg.Section("").Key("INT64").MustInt64()
  16. v = cfg.Section("").Key("UINT").MustUint()
  17. v = cfg.Section("").Key("UINT64").MustUint64()
  18. v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339)
  19. v = cfg.Section("").Key("TIME").MustTime() // RFC3339
  20. // 由 Must 开头的方法名允许接收一个相同类型的参数来作为默认值,
  21. // 当键不存在或者转换失败时,则会直接返回该默认值。
  22. // 但是,MustString 方法必须传递一个默认值。
  23. v = cfg.Section("").Key("String").MustString("default")
  24. v = cfg.Section("").Key("BOOL").MustBool(true)
  25. v = cfg.Section("").Key("FLOAT64").MustFloat64(1.25)
  26. v = cfg.Section("").Key("INT").MustInt(10)
  27. v = cfg.Section("").Key("INT64").MustInt64(99)
  28. v = cfg.Section("").Key("UINT").MustUint(3)
  29. v = cfg.Section("").Key("UINT64").MustUint64(6)
  30. v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339, time.Now())
  31. v = cfg.Section("").Key("TIME").MustTime(time.Now()) // RFC3339

如果我的值有好多行怎么办?

  1. [advance]
  2. ADDRESS = """404 road,
  3. NotFound, State, 5000
  4. Earth"""

嗯哼?小 case!

  1. cfg.Section("advance").Key("ADDRESS").String()
  2. /* --- start ---
  3. 404 road,
  4. NotFound, State, 5000
  5. Earth
  6. ------ end --- */

赞爆了!那要是我属于一行的内容写不下想要写到第二行怎么办?

  1. [advance]
  2. two_lines = how about \
  3. continuation lines?
  4. lots_of_lines = 1 \
  5. 2 \
  6. 3 \
  7. 4

简直是小菜一碟!

  1. cfg.Section("advance").Key("two_lines").String() // how about continuation lines?
  2. cfg.Section("advance").Key("lots_of_lines").String() // 1 2 3 4

可是我有时候觉得两行连在一起特别没劲,怎么才能不自动连接两行呢?

  1. cfg, err := ini.LoadSources(ini.LoadOptions{
  2. IgnoreContinuation: true,
  3. }, "filename")

哇靠给力啊!

需要注意的是,值两侧的单引号会被自动剔除:

  1. foo = "some value" // foo: some value
  2. bar = 'some value' // bar: some value

有时您会获得像从 Crowdin 网站下载的文件那样具有特殊格式的值(值使用双引号括起来,内部的双引号被转义):

  1. create_repo="created repository <a href=\"%s\">%s</a>"

那么,怎么自动地将这类值进行处理呢?

  1. cfg, err := ini.LoadSources(ini.LoadOptions{UnescapeValueDoubleQuotes: true}, "en-US.ini"))
  2. cfg.Section("<name of your section>").Key("create_repo").String()
  3. // You got: created repository <a href="%s">%s</a>

这就是全部了?哈哈,当然不是。

操作键值的辅助方法

获取键值时设定候选值:

  1. v = cfg.Section("").Key("STRING").In("default", []string{"str", "arr", "types"})
  2. v = cfg.Section("").Key("FLOAT64").InFloat64(1.1, []float64{1.25, 2.5, 3.75})
  3. v = cfg.Section("").Key("INT").InInt(5, []int{10, 20, 30})
  4. v = cfg.Section("").Key("INT64").InInt64(10, []int64{10, 20, 30})
  5. v = cfg.Section("").Key("UINT").InUint(4, []int{3, 6, 9})
  6. v = cfg.Section("").Key("UINT64").InUint64(8, []int64{3, 6, 9})
  7. v = cfg.Section("").Key("TIME").InTimeFormat(time.RFC3339, time.Now(), []time.Time{time1, time2, time3})
  8. v = cfg.Section("").Key("TIME").InTime(time.Now(), []time.Time{time1, time2, time3}) // RFC3339

如果获取到的值不是候选值的任意一个,则会返回默认值,而默认值不需要是候选值中的一员。

验证获取的值是否在指定范围内:

  1. vals = cfg.Section("").Key("FLOAT64").RangeFloat64(0.0, 1.1, 2.2)
  2. vals = cfg.Section("").Key("INT").RangeInt(0, 10, 20)
  3. vals = cfg.Section("").Key("INT64").RangeInt64(0, 10, 20)
  4. vals = cfg.Section("").Key("UINT").RangeUint(0, 3, 9)
  5. vals = cfg.Section("").Key("UINT64").RangeUint64(0, 3, 9)
  6. vals = cfg.Section("").Key("TIME").RangeTimeFormat(time.RFC3339, time.Now(), minTime, maxTime)
  7. vals = cfg.Section("").Key("TIME").RangeTime(time.Now(), minTime, maxTime) // RFC3339
自动分割键值到切片(slice)

当存在无效输入时,使用零值代替:

  1. // Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4]
  2. // Input: how, 2.2, are, you -> [0.0 2.2 0.0 0.0]
  3. vals = cfg.Section("").Key("STRINGS").Strings(",")
  4. vals = cfg.Section("").Key("FLOAT64S").Float64s(",")
  5. vals = cfg.Section("").Key("INTS").Ints(",")
  6. vals = cfg.Section("").Key("INT64S").Int64s(",")
  7. vals = cfg.Section("").Key("UINTS").Uints(",")
  8. vals = cfg.Section("").Key("UINT64S").Uint64s(",")
  9. vals = cfg.Section("").Key("TIMES").Times(",")

从结果切片中剔除无效输入:

  1. // Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4]
  2. // Input: how, 2.2, are, you -> [2.2]
  3. vals = cfg.Section("").Key("FLOAT64S").ValidFloat64s(",")
  4. vals = cfg.Section("").Key("INTS").ValidInts(",")
  5. vals = cfg.Section("").Key("INT64S").ValidInt64s(",")
  6. vals = cfg.Section("").Key("UINTS").ValidUints(",")
  7. vals = cfg.Section("").Key("UINT64S").ValidUint64s(",")
  8. vals = cfg.Section("").Key("TIMES").ValidTimes(",")

当存在无效输入时,直接返回错误:

  1. // Input: 1.1, 2.2, 3.3, 4.4 -> [1.1 2.2 3.3 4.4]
  2. // Input: how, 2.2, are, you -> error
  3. vals = cfg.Section("").Key("FLOAT64S").StrictFloat64s(",")
  4. vals = cfg.Section("").Key("INTS").StrictInts(",")
  5. vals = cfg.Section("").Key("INT64S").StrictInt64s(",")
  6. vals = cfg.Section("").Key("UINTS").StrictUints(",")
  7. vals = cfg.Section("").Key("UINT64S").StrictUint64s(",")
  8. vals = cfg.Section("").Key("TIMES").StrictTimes(",")

递归读取键值

在获取所有键值的过程中,特殊语法 %(<name>)s 会被应用,其中 <name> 可以是相同分区或者默认分区下的键名。字符串 %(<name>)s 会被相应的键值所替代,如果指定的键不存在,则会用空字符串替代。您可以最多使用 99 层的递归嵌套。

  1. NAME = ini
  2. [author]
  3. NAME = Unknwon
  4. GITHUB = https://github.com/%(NAME)s
  5. [package]
  6. FULL_NAME = github.com/go-ini/%(NAME)s
  1. cfg.Section("author").Key("GITHUB").String() // https://github.com/Unknwon
  2. cfg.Section("package").Key("FULL_NAME").String() // github.com/go-ini/ini

Python 多行值

如果您刚将服务从 Python 迁移过来,可能会遇到一些使用旧语法的配置文件,别慌!

  1. cfg, err := ini.LoadSources(ini.LoadOptions{
  2. AllowPythonMultilineValues: true,
  3. }, []byte(`
  4. [long]
  5. long_rsa_private_key = -----BEGIN RSA PRIVATE KEY-----
  6. foo
  7. bar
  8. foobar
  9. barfoo
  10. -----END RSA PRIVATE KEY-----
  11. `)
  12. /*
  13. -----BEGIN RSA PRIVATE KEY-----
  14. foo
  15. bar
  16. foobar
  17. barfoo
  18. -----END RSA PRIVATE KEY-----
  19. */