日常开发中读取配置文件包含以下几种格式:

  • json 格式字符串
  • K=V 键值对
  • xml 文件
  • yml 格式文件
  • toml 格式文件

前面两种书写简单,解析过程也比较简单。xml形式书写比较累赘,yml是树形结构,为简化配置而生,toml是一种有着自己语法规则的配置文件格式,我们一一来看使用方式,各位看官自行比较哪种更加实用。

1.读取json格式的文件

package main

import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"sync"
) type Configs map[string]json.RawMessage
var configPath string = "c:/test.json" type MainConfig struct {
Port string `json:"port"`
Address string `json:"address"`
} var conf *MainConfig
var confs Configs var instanceOnce sync.Once //从配置文件中载入json字符串
func LoadConfig(path string) (Configs, *MainConfig) {
buf, err := ioutil.ReadFile(path)
if err != nil {
log.Panicln("load config conf failed: ", err)
}
mainConfig := &MainConfig{}
err = json.Unmarshal(buf, mainConfig)
if err != nil {
log.Panicln("decode config file failed:", string(buf), err)
}
allConfigs := make(Configs, 0)
err = json.Unmarshal(buf, &allConfigs)
if err != nil {
log.Panicln("decode config file failed:", string(buf), err)
} return allConfigs, mainConfig
} //初始化 可以运行多次
func SetConfig(path string) {
allConfigs, mainConfig := LoadConfig(path)
configPath = path
conf = mainConfig
confs = allConfigs
} // 初始化,只能运行一次
func Init(path string) *MainConfig {
if conf != nil && path != configPath {
log.Printf("the config is already initialized, oldPath=%s, path=%s", configPath, path)
}
instanceOnce.Do(func() {
allConfigs, mainConfig := LoadConfig(path)
configPath = path
conf = mainConfig
confs = allConfigs
}) return conf
} //初始化配置文件 为 struct 格式
func Instance() *MainConfig {
if conf == nil {
Init(configPath)
}
return conf
} //初始化配置文件 为 map格式
func AllConfig() Configs {
if conf == nil {
Init(configPath)
}
return confs
} //获取配置文件路径
func ConfigPath() string {
return configPath
} //根据key获取对应的值,如果值为struct,则继续反序列化
func (cfg Configs) GetConfig(key string, config interface{}) error {
c, ok := cfg[key]
if ok {
return json.Unmarshal(c, config)
} else {
return fmt.Errorf("fail to get cfg with key: %s", key)
}
} func main() {
path := ConfigPath()
fmt.Println("path: ",path)
Init(path)
value := confs["port"]
fmt.Println(string(value))
}

json格式文件内容:

{
"port": "7788",
"address": "47.95.34.2"
}

运行结果:

path:  c:/test.json
"7788"

2. 读取key=value类型的配置文件

package main

import (
"bufio"
"io"
"os"
"strings"
) //读取key=value类型的配置文件
func InitConfig(path string) map[string]string {
config := make(map[string]string) f, err := os.Open(path)
defer f.Close()
if err != nil {
panic(err)
} r := bufio.NewReader(f)
for {
b, _, err := r.ReadLine()
if err != nil {
if err == io.EOF {
break
}
panic(err)
}
s := strings.TrimSpace(string(b))
index := strings.Index(s, "=")
if index < 0 {
continue
}
key := strings.TrimSpace(s[:index])
if len(key) == 0 {
continue
}
value := strings.TrimSpace(s[index+1:])
if len(value) == 0 {
continue
}
config[key] = value
}
return config
} func main() {
config := InitConfig("c:/1.txt")
ip := config["ip"]
port := config["port"] fmt.Println("ip=",string(ip)," port=",string(port))
}

配置文件类容:

ip=127.0.0.1
port=3344

运行结果:

ip=127.0.0.1  port=3344

3. 读取yml格式文件

Java中SpringBoot支持使用yml格式的配置文件作为替代properties文件的一种方式。跟properties文件相比,好处就是层级目录,相同的前缀都在该前缀下,前缀只用写一次即可。Go也支持yml文件解析,只是麻烦的程度真的是,,,不想写!

我们先定义一个yml文件:

port: 8080
ip: 127.0.0.1
host: www.baidu.com spring:
redis:
host: redis.dns.baidu.com
port: 6379
dataBase: 0
timeout: 2000

解析代码如下:

package utils

import (
"fmt"
"gopkg.in/yaml.v2"
"io/ioutil"
) //解析yml文件
type BaseInfo struct {
Port string `yaml:"port"`
Ip string `yaml:"ip"`
Host string `yaml:"host"`
Spring RedisEntity `yaml:"spring"`
} type RedisEntity struct {
Redis RedisData `yaml:"redis"`
} type RedisData struct {
Host string `yaml:"host"`
Port string `yaml:"port"`
DataBase string `yaml:"dataBase"`
Timeout string `yaml:"timeout"`
} func (c *BaseInfo) GetConf() *BaseInfo {
yamlFile, err := ioutil.ReadFile("c:/1.yml")
if err != nil {
fmt.Println(err.Error())
}
err = yaml.Unmarshal(yamlFile, c)
if err != nil {
fmt.Println(err.Error())
}
return c
}

解释一下:以上yml文件中是有三层目录结构,所以需要定义三个struct,每个struct分别包含每一层的字段。这样说你应该就能明白如何解析。

运行一下test方法来验证上面程序:

package main

import (
"fmt"
"goProject/src/utils"
"testing"
) func Test(t *testing.T) {
info := utils.BaseInfo{}
conf := info.GetConf()
fmt.Println(conf.Host)
}

可以看到将yml中的树形结构解析为BaseInfo对象。

4. 读取toml格式文件

仿佛我感觉这个比读取yml文件更为痛苦,因为在写toml文件的时候,还有一定的语法规则,仿佛在告诉你别停,继续学习。

TOML 的全称是Tom’s Obvious, Minimal Language,因为它的作者是 GitHub联合创始人Tom Preston-Werner 。 TOML 的目标是成为一个极简的配置文件格式。TOML 被设计成可以无歧义地被映射为哈希表的结构,从而可以被多种语言解析。

举个例子:

port=8080    

[user]
name="xiaoming"
age=14
sex=1 [database]
servers=["127.0.0.1","127.0.0.2","127.0.0.3"]
connection_max=5000
enabled=true [servers]
# 你可以依照你的意愿缩进。使用空格或Tab。TOML不会在意。
[servers.a]
ip="34.23.1.4"
port=6379 [servers.b]
ip="34.23.1.6"
port=9921 #嵌套
[nest]
data=[["n1","n2"],[1,2]] # 在数组里换行没有关系。
names = [
"li",
"wang"
]

下面来解释一下toml格式的书写规范。

首先:TOML 是大小写敏感的。

常见的语法规则:

  1. 注释

    使用 # 表示注释。

  2. 字符串

字符串以""包裹,里面的字符必须是 UTF-8 格式。引号、反斜杠和控制字符(U+0000 到 U+001F)需要转义。

常用的转义序列:

\b     - backspace       (U+0008)
\t - tab (U+0009)
\n - linefeed (U+000A)
\f - form feed (U+000C)
\r - carriage return (U+000D)
\" - quote (U+0022)
\/ - slash (U+002F)
\\ - backslash (U+005C)
\uXXXX - unicode (U+XXXX)
  1. 布尔值

    true

    false

  2. 日期

    使用ISO8601格式日期:

    2019-05-03T22:44:26Z
  3. 数组

    数组使用方括号包裹。空格会被忽略。元素使用逗号分隔。注意,不允许混用数据类型。

    [ 1, 2, 3 ]
    [ "red", "yellow", "green" ]
    [ [ 1, 2 ], [3, 4, 5] ]
    [ [ 1, 2 ], ["a", "b", "c"] ] # 这是可以的。
    [ 1, 2.0 ] # 注意:这是不行的。
  4. 数值类型

    数值类型严格区分整数和浮点数。这两个不是一种类型。

  5. 字典对象

    多个kv集合在一起组成字典对象。字典对象的名字用[]包含起来,单独作为一行。

    解释一下这种格式对应的json格式:

    [servers.a]
    ip="34.23.1.4"
    port=6379 { "servers": { "a": { "ip": "34.23.1.4","port":6379}}}

    我们写一个小程序来解析上面的toml文件:

    package utils
    
    import (
    "fmt"
    "github.com/BurntSushi/toml"
    "io/ioutil"
    "os"
    ) type BaseData struct {
    Db DataBase `toml:"dataBase"`
    Se Servers `toml:"servers"`
    } type DataBase struct {
    Servers []string `toml:"servers"`
    ConnectionMax int `toml:"connection_max"`
    Enabled bool `toml:"enabled"`
    } type Servers struct {
    A ServerEn `toml:"a"`
    B ServerEn `toml:"b"`
    } type ServerEn struct {
    IP string `toml:"ip"`
    Port int `toml:"port"`
    } func ReadConf(fname string) (p *BaseData, err error) {
    var (
    fp *os.File
    fcontent []byte
    )
    p = new(BaseData)
    if fp, err = os.Open(fname); err != nil {
    fmt.Println("open error ", err)
    return
    } if fcontent, err = ioutil.ReadAll(fp); err != nil {
    fmt.Println("ReadAll error ", err)
    return
    } if err = toml.Unmarshal(fcontent, p); err != nil {
    fmt.Println("toml.Unmarshal error ", err)
    return
    }
    return
    }

    注意看我定义的对象,也是逐层解析。

    测试类:

    package main
    
    import (
    "fmt"
    "goProject/src/utils"
    "testing"
    ) func Test(t *testing.T) {
    p, _ := utils.ReadConf("c:/1.toml")
    fmt.Println(p)
    }

Go中配置文件读取的几种方式的更多相关文章

  1. linux内核分析作业4:使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

    系统调用:库函数封装了系统调用,通过库函数和系统调用打交道 用户态:低级别执行状态,代码的掌控范围会受到限制. 内核态:高执行级别,代码可移植性特权指令,访问任意物理地址 为什么划分级别:如果全部特权 ...

  2. JavaScript学习12 JS中定义对象的几种方式

    JavaScript学习12 JS中定义对象的几种方式 JavaScript中没有类的概念,只有对象. 在JavaScript中定义对象可以采用以下几种方式: 1.基于已有对象扩充其属性和方法 2.工 ...

  3. Shell脚本中执行mysql的几种方式(转)

    Shell脚本中执行mysql的几种方式(转) 对于自动化运维,诸如备份恢复之类的,DBA经常需要将SQL语句封装到shell脚本.本文描述了在Linux环境下mysql数据库中,shell脚本下调用 ...

  4. Java中HashMap遍历的两种方式

    Java中HashMap遍历的两种方式 转]Java中HashMap遍历的两种方式原文地址: http://www.javaweb.cc/language/java/032291.shtml 第一种: ...

  5. JAVA中集合输出的四种方式

    在JAVA中Collection输出有四种方式,分别如下: 一) Iterator输出. 该方式适用于Collection的所有子类. public class Hello { public stat ...

  6. android中解析文件的三种方式

    android中解析文件的三种方式     好久没有动手写点东西了,最近在研究android的相关技术,现在就android中解析文件的三种方式做以下总结.其主要有:SAX(Simple API fo ...

  7. python中逐行读取文件的最佳方式_Drupal_新浪博客

    python中逐行读取文件的最佳方式_Drupal_新浪博客 python中逐行读取文件的最佳方式    (2010-08-18 15:59:28)    转载▼    标签:    python   ...

  8. jQuery中开发插件的两种方式

    jQuery中开发插件的两种方式(附Demo) 做web开发的基本上都会用到jQuery,jQuery插件开发两种方式:一种是类扩展的方式开发插件,jQuery添加新的全局函数(jQuery的全局函数 ...

  9. Struts中的数据处理的三种方式

    Struts中的数据处理的三种方式: public class DataAction extends ActionSupport{ @Override public String execute() ...

随机推荐

  1. easyui datagrid 单元格 编辑时 事件 修改另一单元格

    //datagrid 列数据 $('#acc').datagrid({ columns : [ [ { field : 'fee_lend', title : '收费A', width : 100, ...

  2. c++最大公约数

    C++辗转相除法求出最大公因数 样例输入 6 9 样例输出 3 程序 #include <stdio.h> using namespace std; int gcd(int m,int n ...

  3. Docker笔记(一):什么是Docker

    原文地址: http://blog.jboost.cn/2019/07/13/docker-1.html  1. 前言 接触Docker也有两年多了,断断续续玩过一些应用场景,如安装一些常用工具服务, ...

  4. Elasticsearch(一)开启外网访问

    1. 设置Elasticsearch对外访问的Host 修改Elasticsearch配置文件 elasticsearch.yml : network.host: 128.24.108.84  //在 ...

  5. 通俗易懂 悲观锁、乐观锁、可重入锁、自旋锁、偏向锁、轻量/重量级锁、读写锁、各种锁及其Java实现!

    网上关于Java中锁的话题可以说资料相当丰富,但相关内容总感觉是一大串术语的罗列,让人云里雾里,读完就忘.本文希望能为Java新人做一篇通俗易懂的整合,旨在消除对各种各样锁的术语的恐惧感,对每种锁的底 ...

  6. [Asp.net] C# 操作Excel的几种方式 优缺点比较

    在项目中我们常常需要将数据库中的数据导出成Excel文件 有一次工作中我的目的就是读取Excel到内存中,整理成指定格式 整理后再导出到Excel. 因为我要处理的每个Excel表格文件很大.一个表格 ...

  7. o2优化(手动)

    #pragma GCC optimize(2) 将这句话放到程序开头即可

  8. 个人永久性免费-Excel催化剂功能第103波-批量打开多文件或多链接

    有时简单的东西,却带来许多的便利,为了让大家可以记住并容易找寻到此功能,也将这么简单的功能归为一波,反正已经100+波了,也无需为了凑功能文章而故意罗列一些小功能带忽悠性地让人觉得很强大. 使用场景 ...

  9. Storm基础知识学习

    概述 Storm是一个免费开源的分布式实时计算系统.Storm能轻松可靠地处理无界的数据流,就像Hadoop对数据进行批处理 编程模型 spout:数据读取数据.接收数据.将数据写出到blot bol ...

  10. cron 表达式的格式 了解

    cron 表达式的格式 Quartz cron 表达式的格式十分类似于 UNIX cron 格式,但还是有少许明显的区别.区别之一就是 Quartz 的格式向下支持到秒级别的计划,而 UNIX cro ...