golang读写ini文件

1. INI库

1.1. ini文件格式介绍

有默认(空)分区和命名的分区,没有给分区命名就是默认分区默认分区必须写在任何一个命名分区的上边。每个配置项通过换行来区分。

默认分区:类似全局参数

命名分区:类似局部参数

ini格式

1.2. 功能

  • 支持覆盖加载多个数据源(file, []byte, io.Reader and io.ReadCloser
  • 支持递归读取键值
  • 支持读取父子分区
  • 支持读取自增键名
  • 支持读取多行的键值
  • 支持大量辅助方法
  • 支持在读取时直接转换为 Go 语言类型
  • 支持读取和 写入 分区和键的注释
  • 轻松操作分区、键值和注释
  • 在保存文件时分区和键值会保持原有的顺序

1.3. 安装

注:最低要求安装 Go 语言版本为 1.6

go get -v gopkg.in/ini.v1

1.4. 快速开始

  • config.ini
app_name = blog

# possible values: DEBUG, INFO, WARNING, ERROR, FATAL
log_level = DEBUG
domain = google.com

[mysql]
domain = baidu.com
ip = %(domain)s
port = 3306
user = hallen
password = 123456
database = blog

[redis]
ip = %(domain)s
port = 6379
  • main.go
package main
import (
    "fmt"
    "gopkg.in/ini.v1"
)
func main() {
    cfg, err := ini.Load("./config.ini")
    if err != nil {
        fmt.Printf("读取配置文件出错... :%v\n", err)
        return
    }

    //##############读取ini文件的方法###################
    // 典型读取操作,默认分区可以使用空字符串表示
  fmt.Println("APP NAME :", cfg.Section("").Key("app_name").String())

    fmt.Println("MYSQL IP:", cfg.Section("mysql").Key("ip").String())
    fmt.Println("MYSQL PORT:", cfg.Section("mysql").Key("port").String())
    fmt.Println("REDIS IP:", cfg.Section("redis").Key("ip").String())
    /*输出结果
    APP NAME : blog
    MYSQL IP: baidu.com
    MYSQL PORT: 3306
    REDIS IP: google.com
    */

    //##############修改ini文件的方法###################
    // 修改后,修改某个值然后进行保存。
    // 修改默认分区节点的数据
    cfg.Section("").Key("log_level").SetValue("DEV")

    // 修改有节点的数据的方式
    cfg.Section("redis").Key("port").SetValue("6378")
  // 保存修改
    cfg.SaveTo("./config.ini")
}

2. 数据源加载

2.1. Load

cfg, err := ini.Load("./config.ini")
if err != nil {
  fmt.Printf("读取配置文件出错... :%v\n", err)
  return
}

2.2. ShadowLoad

ShadowLoad()具有与Load()函数完全相同的功能,只是它允许读取同名Key(同个键名包含多个值)。

cfg, err := ini.ShadowLoad("./config.ini")
if err != nil {
  fmt.Printf("读取配置文件出错... :%v\n", err)
  return
}
/* config.ini
[remote]
url = https://github.com/test1.git
url = https://github.com/test2.git
*/
cfg.Section("remote").Key("url").ValueWithShadows()
// Result:  []string{
//              "https://github.com/test1.git",
//              "https://github.com/test2.git",
//          }

3. 读取数据

3.1. 操作分区(Section)

3.1.1. 获取所有分区

//获取所有分区对象
secs := cfg.Sections()

//获取所有分区名称
names := cfg.SectionStrings()

3.1.2. 指定分区

GetSection()Section()功能一样。只是Section()如果没找到分区,会自动创建一个分区保存在ini文件,GetSection()不会

3.1.2.1. GetSection
sec, err := cfg.GetSection("mysql")
3.1.2.2. Section
//获取指定分区
sec := cfg.Section("mysql")

//获取默认分区,使用空字符串代替分区名
sec := cfg.Section("")

3.2. 操作键(Key)

3.2.1. 获取所有键名

//获取所有键名
names := cfg.Section("mysql").KeyStrings()

3.2.2. 指定键

GetKey()Key()功能一样。只是Key()如果没找到分区,会自动创建一个Key保存在ini文件,GetKey()不会

3.2.2.1. GetKey
key, err := cfg.Section("mysql").GetKey("ip")
3.2.2.2. Key
key := cfg.Section("mysql").Key("ip")

3.3. 操作键值(Value)

3.3.1. 获取所有键值

//获取所有键值
keys := cfg.Section("mysql").Keys()

3.3.2. 获取指定键值

3.3.2.1. 获取原值
val := cfg.Section("mysql").Key("ip").Value()
3.3.2.2. 获取类型转换值
// 布尔值的规则:
// true 当值为:1, t, T, TRUE, true, True, YES, yes, Yes, y, ON, on, On
// false 当值为:0, f, F, FALSE, false, False, NO, no, No, n, OFF, off, Off
val := cfg.Section("").Key("key name").String()

v, err = cfg.Section("").Key("BOOL").Bool()
v, err = cfg.Section("").Key("FLOAT64").Float64()
v, err = cfg.Section("").Key("INT").Int()
v, err = cfg.Section("").Key("INT64").Int64()
v, err = cfg.Section("").Key("UINT").Uint()
v, err = cfg.Section("").Key("UINT64").Uint64()
v, err = cfg.Section("").Key("TIME").TimeFormat(time.RFC3339)
v, err = cfg.Section("").Key("TIME").Time() // RFC3339

// 由 Must 开头的方法名允许接收一个相同类型的参数来作为默认值,
// 当键不存在或者转换失败时,则会直接返回该默认值。
// 但是,MustString 方法必须传递一个默认值。
v = cfg.Section("").Key("String").MustString("default")
v = cfg.Section("").Key("BOOL").MustBool()
v = cfg.Section("").Key("FLOAT64").MustFloat64()
v = cfg.Section("").Key("INT").MustInt()
v = cfg.Section("").Key("INT64").MustInt64()
v = cfg.Section("").Key("UINT").MustUint()
v = cfg.Section("").Key("UINT64").MustUint64()
v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339)
v = cfg.Section("").Key("TIME").MustTime() // RFC3339

3.3.3. 占位符

在配置文件中,可以使用占位符%(domain)s表示用之前已定义的键domain的值来替换,这里的s表示值为字符串类型。如果某个键在子分区中不存在,则会在它的父分区中再次查找,直到没有父分区为止,就近原则。

快速开始中,可以看到例子。

4. 写入数据

4.1. 修改键值(Value)

//修改数据
cfg.Section("redis").Key("port").SetValue("6378")
//保存
cfg.SaveTo("./config.ini")

5. 结构体与分区双向映射

5.1. Struct Tag

type Embeded struct {
    Dates  []time.Time `delim:"|" comment:"Time data"` //delim:设置分隔符,默认为逗号;comment:注释
    Places []string    `ini:"places,omitempty"`        //omitempty:如果数据为空不映射值
    None   []int       `ini:",omitempty"`              //`ini:字段名,是否忽略空值,allowshadow`
}

type Author struct {
    Name      string `ini:"NAME"`
    Male      bool
    Age       int `comment:"Author's age"`
    GPA       float64
    NeverMind string `ini:"-"` //-:忽略该字段
    *Embeded  `comment:"Embeded section"`
}

5.2. 文件映射到结构

5.2.1. MapTo

package main

import (
    "fmt"

    "gopkg.in/ini.v1"
)

type Conf struct {
    AppName  string `ini:"app_name"`
    LogLevel string `ini:"log_level"`
    Domain   string `ini:"domain"`
    Mysql    `ini:"mysql"`
    Redis    `ini:"redis"`
}

type Mysql struct {
    Domain   string `ini:"domain"`
    IP       string `ini:"ip"`
    Port     string `ini:"port"`
    User     string `ini:"user"`
    Password string `ini:"password"`
    Database string `ini:"-"` 
}

type Redis struct {
    IP   string `ini:"ip"`
    Port string `ini:"port"`
    User string `ini:"user"`
}

func main() {
    cfg, err := ini.Load("./config.ini")
    if err != nil {
        fmt.Printf("读取配置文件出错... :%v\n", err)
        return
    }

    config := &Conf{
        //设置默认值,如果键未找到或者类型错误,才会赋值。否则使用原值
        Redis: Redis{
            Port: "2233",
            User: "redis_user",
        },
    }
    err = cfg.MapTo(config)

    if err != nil {
        fmt.Println("cfg.MapTo err :", err)
    }
    fmt.Println(config)
    //&{blog DEBUG google.com {baidu.com baidu.com 3306 hallen 123456 } {google.com 6379 redis_user}}
}

5.3. 结构体反射到文件

5.3.1. ReflectFrom

通过Struct Tag反射,保存生成ini文件

package main

import (
    "time"

    "gopkg.in/ini.v1"
)

type Embeded struct {
  Dates  []time.Time `delim:"|" comment:"Time data"`
  Places []string    `ini:"places,omitempty"` 
    None   []int       `ini:",omitempty"`
}

type Author struct {
    Name      string `ini:"NAME"`
    Male      bool
    Age       int `comment:"Author's age"`
    GPA       float64
  NeverMind string `ini:"-"`
    *Embeded  `comment:"Embeded section"`
}

func main() {
    a := &Author{"Unknwon", true, 21, 2.8, "",
        &Embeded{
            []time.Time{time.Now(), time.Now()},
            []string{"HangZhou", "Boston"},
            []int{},
        }}
    cfg := ini.Empty()
    err := ini.ReflectFrom(cfg, a)
    if err != nil {
        return
    }
  //保存文件
    cfg.SaveTo("./test.ini")
}
  • test.ini
NAME = Unknwon
Male = true
; Author's age
Age  = 21
GPA  = 2.8

; Embeded section
[Embeded]
; Time data
Dates  = 2022-11-17T14:38:02+08:00|2022-11-17T14:38:02+08:00
places = HangZhou,Boston
作者: Hountry_Liu
本文采用 CC BY-NC-SA 4.0 协议
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇
EA PLAYER &

历史记录 [ 注意:部分数据仅限于当前浏览器 ]清空

      00:00/00:00