Go中解析配置文件demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package main

import (
"fmt"
"io/ioutil"
"reflect"
"strconv"
"strings"
)

// Config 日志文件结构体
type Config struct {
Level string `conf:"level"`
Filepath string `conf:"filepath"`
Filename string `conf:"filename"`
Maxsize int64 `conf:"maxsize"`
}

func parseConf(fileName string, result interface{}) (err error) {
t := reflect.TypeOf(result)
v := reflect.ValueOf(result)
if t.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
err = fmt.Errorf("result必须是一个指针且是结构体指针")
return
}
data, err := ioutil.ReadFile(fileName)
if err != nil {
err = fmt.Errorf("打开配置文件%s失败", fileName)
return
}
lineSlice := strings.Split(string(data), "\r\n")
resMap := map[string]string{}
for index, line := range lineSlice {
//去除收尾空格
line = strings.TrimSpace(line)
//排查空行或注释行
if line == "" || strings.HasPrefix(line, "#") {
continue
}
//排查不含=的行
eqIndex := strings.Index(line, "=")
if eqIndex == -1 {
err = fmt.Errorf("第%d行有语法错误", index+1)
return
}
//排查没有key的行 比如 =dsfafads
//Trim 去除收尾指定字符串
//TrimSpace 去除收尾空格
key := strings.ToLower(strings.TrimSpace(line[:eqIndex]))
//去除首尾双引号"
val := strings.Trim(strings.TrimSpace(line[eqIndex+1:]), "\"")
if key == "" {
err = fmt.Errorf("第%d行有语法错误", index+1)
return
}
resMap[key] = val
}
//结构体反射 reflect.TypeOf(result) 下的方法
//Elem()方法获取指针对应的值
tElem := t.Elem()
vElem := v.Elem()
for i := 0; i < tElem.NumField(); i++ {
// 取到结构体字段信息
field := tElem.Field(i)
// 通过字段名取到tag
tagName := field.Tag.Get("conf")
switch field.Type.Kind() {
case reflect.String:
//再找到值信息设置值
vElem.Field(i).SetString(resMap[tagName])
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
//将任意类型转换为Int64
val64, _ := strconv.ParseInt(resMap[tagName], 10, 64)
vElem.Field(i).SetInt(val64)
}
}
return
}

func main() {
c := &Config{}
err := parseConf("config.conf", c)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(c.Level)
fmt.Println(c.Filename)
fmt.Println(c.Filepath)
fmt.Println(c.Maxsize)
}