實作練習-ini解析器
尚硅谷Golang課
用來解析.ini文檔格式是否有問題
package main
import (
"fmt"
"io/ioutil"
"reflect"
"strings"
)
type RedisConfig struct {
Host string `ini:"host"`
Port int `ini:"port"`
Password string `ini:"password"`
Database int `ini:"database"`
}
type MysqlConfig struct {
Address string `ini:"address"`
Port int `ini:"port"`
Password string `ini:"password"`
Username string `ini:"username"`
}
type Config struct {
MysqlConfig `ini:"mysql"`
RedisConfig `ini:"redis"`
}
func loadIni(fileName string, data interface{}) (err error) {
// 0. 參數校驗
// 0.1 傳來的data必須是結構體類型指針
t := reflect.TypeOf(data)
// fmt.Println(t.Kind())
if t.Kind() != reflect.Ptr {
err = fmt.Errorf("傳來的data必須是指針")
return
}
if t.Elem().Kind() != reflect.Struct {
err = fmt.Errorf("傳來的data必須是結構體類型指針")
return
}
// 1. 讀取文件~>Byte類型
b, err := ioutil.ReadFile(fileName)
if err != nil {
return
}
//轉成字符串
lineSlice := strings.Split(string(b), "\r\n")
// fmt.Println(lineSlice)
// 2. 一行一行讀取數據
var structName string
for idx, line := range lineSlice {
line = strings.TrimSpace(line) //去除多餘空格
// 2.1 如果是註釋就跳過
if strings.HasPrefix(line, ";") || strings.HasPrefix(line, "#") {
continue
}
//純空行就跳過
if len(line) == 0 {
continue
}
// 2.2 如果是[]開頭表示是節
if strings.HasPrefix(line, "[") {
if line[0] != '[' || line[len(line)-1] != ']' {
err = fmt.Errorf("line:%d syntax error", idx+1)
return
}
//去掉這行的首尾跟空格拿到內容
section := strings.TrimSpace(line[1 : len(line)-1])
if len(section) == 0 {
err = fmt.Errorf("line:%d syntax error", idx+1)
return
}
//根據section去data反射對應的結構體
for i := 0; i < t.Elem().NumField(); i++ {
field := t.Elem().Field(i)
if section == field.Tag.Get("ini") {
//說明找到了,把字段名記下
structName = field.Name
fmt.Println(section, structName)
}
}
} else {
// 2.3 剩下的就是分割的鍵值對
//先排除異常的行
if strings.Index(line, "=") == -1 || strings.HasPrefix(line, "=") {
err = fmt.Errorf("line:%d syntax error", idx+1)
return
}
index := strings.Index(line, "=")
key := strings.TrimSpace(line[:index])
// value := strings.TrimSpace(line[:index+1])
v := reflect.ValueOf(data)
sValue := v.Elem().FieldByName(structName) //拿到嵌套結構體的值信息
sType := sValue.Type() //拿到嵌套結構體的類型信息
if sType.Kind() != reflect.Struct {
err = fmt.Errorf("%s應該為一個結構體", structName)
return
}
var fieldName string
//遍歷嵌套結構體每一個字段 判斷tag是否=key
for i := 0; i < sValue.NumField(); i++ {
field := sType.Field(i)
if field.Tag.Get("ini") == key {
fieldName = field.Name
break
}
}
//根據fieldName取出字段賦值
fileObj := sValue.FieldByName(fieldName)
fmt.Println(fieldName, fileObj)
}
}
return
}
func main() {
var cfg Config
err := loadIni("C:/config.ini", &cfg)
if err != nil {
panic(err)
}
}
上次修改於 2021-08-01
此篇文章的評論功能已經停用。