超赞的 Go 语言 INI 文件操作

前言

INI 是 Windows 上常用的配置文件格式。如果你使用 INI 作为系统的配置文件,那么一定会使用这个库吧。它就是号称地表 最强大、最方便 和 最流行 的 Go 语言 INI 文件操作库。配置文件形式为[section] 的段构成, 内部使用 name=value键值对 。go-ini是 Go 语言中用于操作 ini 文件的第三方库。本文介绍go-ini库的使用。

INI官方

该项目的作者也是很多 Go 语言爱好者熟悉的无闻大师。讲真,文档都写的很好,很用心。

官方网站:https://ini.unknwon.io/

超赞的 Go 语言 INI 文件操作_第1张图片

功能特性

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

安装下载

go-ini 是第三方库,使用前需要安装,最低要求安装 Go 语言版本为 1.6。安装时切换到root用户,否则会报错(permission denied)。

安装:

go get gopkg.in/ini.v1

则gopkg.in会出现在src目录下:
在这里插入图片描述
也可以使用 GitHub 上的仓库:

go get github.com/go-ini/ini

开始使用

我们将通过一个非常简单的例子来了解如何使用。首先,我们需要在src目录下,任意创建两个文件(my.ini 和 main.go)。

首先,创建一个my.ini配置文件:

app_name = awesome web

# possible values: DEBUG, INFO, WARNING, ERROR, FATAL
log_level = DEBUG

[mysql]
ip = 127.0.0.1
port = 3306
user = minger
password = 123456
database = awesome

[redis]
ip = 127.0.0.1
port = 6379

在 ini 文件中,每个键值对占用一行,中间使用=隔开。以#开头的内容为注释。ini 文件是以分区(section)组织的。在下一个分区前结束。所有分区前的内容属于默认分区,如my.ini文件中的app_name和log_level。

接下来我们需要编写 main.go 文件来操作刚才创建的my.ini配置文件。

package main

import (
  "fmt"
  "log"

  "gopkg.in/ini.v1"
)

func main() {
  cfg, err := ini.Load("my.ini")
  if err != nil {
    log.Fatal("Fail to read file: ", err)
  }

  // 典型读取操作,默认分区可以使用空字符串表示
  fmt.Println("App Name:", cfg.Section("").Key("app_name").String())
  fmt.Println("Log Level:", cfg.Section("").Key("log_level").String())

   //获取一个类型为字符串(string)的值
  fmt.Println("MySQL IP:", cfg.Section("mysql").Key("ip").String())
   //获取一个类型为整形(int)的值
  mysqlPort, err := cfg.Section("mysql").Key("port").Int()
  if err != nil {
    log.Fatal(err)
  }
  fmt.Println("MySQL Port:", mysqlPort)
  fmt.Println("MySQL User:", cfg.Section("mysql").Key("user").String())
  fmt.Println("MySQL Password:", cfg.Section("mysql").Key("password").String())
  fmt.Println("MySQL Database:", cfg.Section("mysql").Key("database").String())

  //go-ini也提供对应的MustType(Type 为Init/Uint/Float64等)方法,这个方法只返回一个值。
  //fmt.Println("redis Port:", cfg.Section("redis").Key("port").MustInt(6381))

  //获取一个类型为字符串(string)的值
  fmt.Println("Redis IP:", cfg.Section("redis").Key("ip").String())
  redisPort, err := cfg.Section("redis").Key("port").Int()
  if err != nil {
    log.Fatal(err)
  }
  fmt.Println("Redis Port:", redisPort)
}

编译输出:

超赞的 Go 语言 INI 文件操作_第2张图片
从上面的信息,配置文件中存储的都是字符串,所以类型为字符串的配置项不会出现类型转换失败的,故String()方法只返回一个值。
但如果类型为Int/Uint/Float64这些时,转换可能失败。

使用go-ini读取配置文件的步骤如下:


1、首先调用ini.Load加载文件,得到配置对象cfg;

2、然后以分区名调用配置对象的Section方法得到对应的分区对象section,默认分区的名字为"",也可以使用ini.DefaultSection;

3、以键名调用分区对象的Key方法得到对应的配置项key对象;

4、由于文件中读取出来的都是字符串,key对象需根据类型调用对应的方法返回具体类型的值使用,如上面的String、MustInt方法。

分区操作

在加载配置之后,可以通过Sections方法获取所有分区,SectionStrings()方法获取所有分区名。例如:

package main

import (
  "fmt"
  "os"

  "gopkg.in/ini.v1"
)

func main() {

    cfg, err := ini.Load("my.ini")
    if err != nil {
        fmt.Printf("Fail to read file: %v", err)
        os.Exit(1)
    }

    sections := cfg.Sections()
    names := cfg.SectionStrings()
    
    fmt.Println("sections: ", sections)
    fmt.Println("names: ", names)
}

编译输出:

超赞的 Go 语言 INI 文件操作_第3张图片
调用Section(name)获取名为name的分区,如果该分区不存在,则自动创建一个分区返回,例子如下:

package main

import (
  "fmt"
  "os"

  "gopkg.in/ini.v1"
)

func main() {

    cfg, err := ini.Load("my.ini")
    if err != nil {
        fmt.Printf("Fail to read file: %v", err)
        os.Exit(1)
    }

    newSection := cfg.Section("new")

    fmt.Println("new section: ", newSection)
    fmt.Println("names: ", cfg.SectionStrings())
}

编译输出:

在这里插入图片描述

保存配置

有时候,我们需要将生成的配置写到文件中。例如在写工具的时候。保存有两种类型的接口,一种直接保存到文件,另一种写入到io.Writer中:

下面我们通过程序生成前面使用的配置文件my.ini并保存:

package main

import (
  "fmt"
  "os"

  "gopkg.in/ini.v1"
)

func main() {
  cfg := ini.Empty()

  defaultSection := cfg.Section("")
  defaultSection.NewKey("app_name", "awesome web")
  defaultSection.NewKey("log_level", "DEBUG")

  mysqlSection, err := cfg.NewSection("mysql")
  if err != nil {
    fmt.Println("new mysql section failed:", err)
    return
  }
  mysqlSection.NewKey("ip", "127.0.0.1")
  mysqlSection.NewKey("port", "3306")
  mysqlSection.NewKey("user", "root")
  mysqlSection.NewKey("password", "123456")
  mysqlSection.NewKey("database", "awesome")

  redisSection, err := cfg.NewSection("redis")
  if err != nil {
    fmt.Println("new redis section failed:", err)
    return
  }
  redisSection.NewKey("ip", "127.0.0.1")
  redisSection.NewKey("port", "6379")

  err = cfg.SaveTo("my.ini")
  if err != nil {
    fmt.Println("SaveTo failed: ", err)
  }

  err = cfg.SaveToIndent("my-pretty.ini", "\t") //保存文件为 my-pretty.ini
  if err != nil {
    fmt.Println("SaveToIndent failed: ", err)
  }

  cfg.WriteTo(os.Stdout)
  fmt.Println()
//   cfg.WriteToIndent(os.Stdout, "\t")
}

编译输出:

超赞的 Go 语言 INI 文件操作_第4张图片
my-pretty.ini

超赞的 Go 语言 INI 文件操作_第5张图片
下面来看看分区与结构体字段映射的使用。

分区与结构体字段映射

我们将通过一个非常简单的例子来了解分区与结构体字段映射如何使用。例如:

package main

import (
  "fmt"

  "gopkg.in/ini.v1"
)

type Config struct {
  AppName   string `ini:"app_name"`
  LogLevel  string `ini:"log_level"`

  MySQL     MySQLConfig `ini:"mysql"`
  Redis     RedisConfig `ini:"redis"`
}

type MySQLConfig struct {
  IP        string `ini:"ip"`
  Port      int `ini:"port"`
  User      string `ini:"user"`
  Password  string `ini:"password"`
  Database  string `ini:"database"`
}

type RedisConfig struct {
  IP      string `ini:"ip"`
  Port    int `ini:"port"`
}

func main() {
  cfg, err := ini.Load("my.ini")
  if err != nil {
    fmt.Println("load my.ini failed: ", err)
  }

  c := Config{}
  cfg.MapTo(&c)

  fmt.Println(c)
}

编译输出:

超赞的 Go 语言 INI 文件操作_第6张图片
MapTo内部使用了反射,所以结构体字段必须都是导出的。如果键名与字段名不相同,那么需要在结构标签中指定对应的键名。

结构体生成配置

package main

import (
  "fmt"
  "os"

  "gopkg.in/ini.v1"
)

type Config struct {
  AppName   string `ini:"app_name"`
  LogLevel  string `ini:"log_level"`

  MySQL     MySQLConfig `ini:"mysql"`
  Redis     RedisConfig `ini:"redis"`
}

type MySQLConfig struct {
  IP        string `ini:"ip"`
  Port      int `ini:"port"`
  User      string `ini:"user"`
  Password  string `ini:"password"`
  Database  string `ini:"database"`
}

type RedisConfig struct {
  IP      string `ini:"ip"`
  Port    int `ini:"port"`
}

func main() {
  cfg, err := ini.Load("my.ini")
  if err != nil {
    fmt.Println("load my.ini failed: ", err)
  }

  cfg = ini.Empty()

  c := Config {
    AppName:     "awesome web",
    LogLevel:     "DEBUG",
    MySQL: MySQLConfig {
      IP:     "127.0.0.1",
      Port:    3306,
      User:    "root",
      Password:"123456",
      Database:"awesome",
    },
    Redis: RedisConfig {
      IP:        "127.0.0.1",
      Port:    6379,
    },
  }
  
  err = ini.ReflectFrom(cfg, &c)
  if err != nil {
    fmt.Println("ReflectFrom failed: ", err)
    return
  }
  
  err = cfg.SaveTo("my-copy.ini")
  if err != nil {
    fmt.Println("SaveTo failed: ", err)
    return
  }

  cfg.WriteTo(os.Stdout)
  fmt.Println()

}

编译输出:
超赞的 Go 语言 INI 文件操作_第7张图片

总结

go-ini 是 Go 语言中用于操作 ini 文件的第三方库。go-ini还有很多高级特性。官方文档非常详细,推荐去看一看。

参考:go-ini 官方文档
go-ini GitHub 仓库
https://studygolang.com/articles/26135

超赞的 Go 语言 INI 文件操作_第8张图片

欢迎关注公众号【程序猿编码】,添加本人微信号(17865354792),回复:领取学习资料,网盘资料有如下:

超赞的 Go 语言 INI 文件操作_第9张图片

你可能感兴趣的:(Go)