首页 体育 教育 财经 社会 娱乐 军事 国内 科技 互联网 房产 国际 女人 汽车 游戏

Go 每日一库之 go

2020-01-18

ini 是 Windows 上常用的装备文件格局。MySQL 的 Windows 版便是运用 ini 格局存储装备的。

go-ini 是 Go 言语中用于操作 ini 文件的第三方库。

本文介绍 go-ini 库的运用。

go-ini 是第三方库,运用前需求装置:

$ go get gopkg.in/ini.v1

也能够运用 GitHub 上的库房:

$ go get github.com/go-ini/ini

首要,创立一个 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 = dj
password = 123456
database = awesome
[redis]
ip = 127.0.0.1
port = 6381

运用 go-ini 库读取:

package main
import  {
 cfg, err := ini.Load
 if err != nil {
 log.Fatal
 fmt.Println.Key.String)
 fmt.Println.Key.String)
 fmt.Println.Key.String)
 mysqlPort, err := cfg.Section.Key.Int
 if err != nil {
 log.Fatal
 fmt.Println
 fmt.Println.Key.String)
 fmt.Println.Key.String)
 fmt.Println.Key.String)
 fmt.Println.Key.String)
 redisPort, err := cfg.Section.Key.Int
 if err != nil {
 log.Fatal
 fmt.Println
}

在 ini 文件中,每个键值对占用一行,中心运用 = 离隔。以 # 最初的内容为注释。ini 文件是以分区安排的。

分区以 [name] 开端,鄙人一个分区前完毕。一切分区前的内容归于默许分区,如 my.ini 文件中的 app_name 和 log_level 。

运用 go-ini 读取装备文件的过程如下:

运转以下程序,得到输出:

App Name: awesome web
Log Level: DEBUG
MySQL IP: 127.0.0.1
MySQL Port: 3306
MySQL User: dj
MySQL Password: 123456
MySQL Database: awesome
Redis IP: 127.0.0.1
Redis Port: 6381

装备文件中存储的都是字符串,所以类型为字符串的装备项不会呈现类型转化失利的,故 String 办法只回来一个值。

但假如类型为 Int/Uint/Float64 这些时,转化或许失利。所以 Int/Uint/Float64 回来一个值和一个过错。

要留心这种不一致!假如咱们将装备中 redis 端口改成不合法的数字 x6381,那么运转程序将报错:

2020/01/14 22:43:13 strconv.ParseInt: parsing x6381 : invalid syntax

假如每次取值都需求进行过错判断,那么代码写起来会十分繁琐。为此, go-ini 也供给对应的 MustType 办法,这个办法只回来一个值。

一同它承受可变参数,假如类型无法转化,取参数中第一个值回来,并且该参数设置为这个装备的值,下次调用回来这个值:

package main
import  {
 cfg, err := ini.Load
 if err != nil {
 log.Fatal
 redisPort, err := cfg.Section.Key.Int
 if err != nil {
 fmt.Println
 } else {
 fmt.Println
 fmt.Println.Key.MustInt)
 redisPort, err = cfg.Section.Key.Int
 if err != nil {
 fmt.Println
 } else {
 fmt.Println
}

装备文件仍是 redis 端口为非数字 x6381 时的状况,运转程序:

before must, get redis port error: strconv.ParseInt: parsing x6381 : invalid syntax
redis Port: 6381
after must, get redis port: 6381

咱们看到第一次调用 Int 回来过错,以 6381 为参数调用 MustInt 之后,再次调用 Int ,成功回来 6381。 MustInt 源码也比较简单:

// gopkg.in/ini.v1/key.go
func  MustInt int {
 val, err := k.Int
 if len 0 err != nil {
 k.value = strconv.FormatInt, 10)
 return defaultVal[0]
 return val
}

在加载装备之后,能够经过 Sections 办法获取一切分区, SectionStrings 办法获取一切分区名。

sections := cfg.Sections
names := cfg.SectionStrings
fmt.Println
fmt.Println

运转输出 3 个分区:

[DEFAULT mysql redis]

调用 Section 获取名为 name 的分区,假如该分区不存在,则主动创立一个分区回来:

newSection := cfg.Section
fmt.Println
fmt.Println)

创立之后调用 SectionStrings 办法,新分区也会回来:

names: [DEFAULT mysql redis new]

也能够手动创立一个新分区,假如分区已存在,则回来过错:

err := cfg.NewSection

在装备文件中,能够运用占位符 %s 表明用之前已界说的键 name 的值来替换,这儿的 s 表明值为字符串类型:

NAME = ini
VERSION = v1
IMPORT_PATH = gopkg.in/%s.%s
[package]
CLONE_URL = https://%s
[package.sub]

上面在默许分区中设置 IMPORT_PATH 的值时,运用了前面界说的 NAME 和 VERSION 。

在 package 分区中设置 CLONE_URL 的值时,运用了默许分区中界说的 IMPORT_PATH 。

咱们还能够在分区名中运用 . 表明两个或多个分区之间的父子关系,例如 package.sub 的父分区为 package , package 的父分区为默许分区。

假如某个键在子分区中不存在,则会在它的父分区中再次查找,直到没有父分区停止:

cfg, err := ini.Load
if err != nil {
 fmt.Println
 return
fmt.Println.Key.String)

运转程序输出:

Clone url from package.sub: https://gopkg.in/ini.v1

子分区中 package.sub 中没有键 CLONE_URL ,回来了父分区 package 中的值。

有时分,咱们需求将生成的装备写到文件中。例如在写东西的时分。保存有两种类型的接口,一种直接保存到文件,另一种写入到 io.Writer 中:

err = cfg.SaveTo
err = cfg.SaveToIndent
cfg.WriteTo
cfg.WriteToIndent

下面咱们经过程序生成前面运用的装备文件 my.ini 并保存:

package main
import  {
 cfg := ini.Empty
 defaultSection := cfg.Section
 defaultSection.NewKey
 defaultSection.NewKey
 mysqlSection, err := cfg.NewSection
 if err != nil {
 fmt.Println
 return
 mysqlSection.NewKey
 mysqlSection.NewKey
 mysqlSection.NewKey
 mysqlSection.NewKey
 mysqlSection.NewKey
 redisSection, err := cfg.NewSection
 if err != nil {
 fmt.Println
 return
 redisSection.NewKey
 redisSection.NewKey
 err = cfg.SaveTo
 if err != nil {
 fmt.Println
 err = cfg.SaveToIndent
 if err != nil {
 fmt.Println
 cfg.WriteTo
 fmt.Println
 cfg.WriteToIndent
}

运转程序,生成两个文件 my.ini 和 my-pretty.ini ,一同控制台输出文件内容。

my.ini :

app_name = awesome web
log_level = DEBUG
[mysql]
ip = 127.0.0.1
port = 3306
user = root
password = 123456
database = awesome
[redis]
ip = 127.0.0.1
port = 6381

my-pretty.ini :

app_name = awesome web
log_level = DEBUG
[mysql]
 ip = 127.0.0.1
 port = 3306
 user = root
 password = 123456
 database = awesome
[redis]
 ip = 127.0.0.1
 port = 6381

*Indent 办法会对子分区下的键添加缩进,看起来漂亮一点。

界说结构变量,加载完装备文件后,调用 MapTo 将装备项赋值到结构变量的对应字段中。

package main
import  {
 cfg, err := ini.Load
 if err != nil {
 fmt.Println
 c := Config{}
 cfg.MapTo
 fmt.Println
}

MapTo 内部运用了反射, 所以结构体字段有必要都是导出的 。假如键名与字段名不相同,那么需求在结构标签中指定对应的键名。

这一点与 Go 规范库 encoding/json 和 encoding/xml 不同。规范库 json/xml 解析时能够将键名 app_name 对应到字段名 AppName 。

或许这是 go-ini 库能够优化的点?

先加载,再映射有点繁琐,直接运用 ini.MapTo 将两步兼并:

err = ini.MapTo

也能够只映射一个分区:

mysqlCfg := MySQLConfig{}
err = cfg.Section.MapTo

还能够经过结构体生成装备:

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: 6381,
err := ini.ReflectFrom
if err != nil {
 fmt.Println
 return
err = cfg.SaveTo
if err != nil {
 fmt.Println
 return
}

本文介绍了 go-ini 库的根本用法和一些风趣的特性。示例代码已上传 GitHub 。

其实 go-ini 还有许多高档特性。 官方文档 十分具体,引荐去看,并且有中文哟~

作者 无闻 ,信任做 Go 开发的都不生疏。

我的博客

欢迎重视我的微信大众号,一同学习,一同前进~

本文由博客一文多发渠道 OpenWrite 发布!

热门文章

随机推荐

推荐文章