2024-07-02 18:19:18 +08:00
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"os"
|
2024-07-02 21:48:33 +08:00
|
|
|
|
"strconv"
|
2024-07-02 18:19:18 +08:00
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
"reflect"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
//定义结构体
|
|
|
|
|
|
|
|
|
|
type MysqlConfig struct {
|
|
|
|
|
Address string `ini:"address"`
|
|
|
|
|
Port int `ini:"port"`
|
|
|
|
|
Username string `ini:"username"`
|
|
|
|
|
Password string `ini:"password"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type RedisConfig struct {
|
2024-07-02 21:48:33 +08:00
|
|
|
|
Host string `ini:"host"`
|
2024-07-02 18:19:18 +08:00
|
|
|
|
Port int `ini:"port"`
|
|
|
|
|
Password string `ini:"password"`
|
|
|
|
|
Database string `ini:"database"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Config struct {
|
2024-07-02 21:48:33 +08:00
|
|
|
|
MysqlConfig `ini:"mysql"`
|
|
|
|
|
RedisConfig `ini:"redis"`
|
2024-07-02 18:19:18 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Loadini(fileName string, data interface{}) (err error) {
|
|
|
|
|
//0.参数的校验,对函数中修改值,必须是结构体指针
|
|
|
|
|
t := reflect.TypeOf(data)
|
2024-07-02 21:48:33 +08:00
|
|
|
|
v := reflect.ValueOf(data)
|
2024-07-02 18:19:18 +08:00
|
|
|
|
//校验指针类型
|
|
|
|
|
if t.Kind() != reflect.Ptr {
|
|
|
|
|
err = fmt.Errorf("data should be pointer")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
//校验结构体类型,由于是指针,要用elem方法
|
|
|
|
|
if t.Elem().Kind() != reflect.Struct {
|
|
|
|
|
err = fmt.Errorf("data should be struct")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
//1.读取文件
|
|
|
|
|
b, err := os.ReadFile(fileName) //读取文件拿到字节类型的数据
|
|
|
|
|
if err != nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lineSlice := strings.Split(string(b), "\r\n") //字节类型的数据按照换行符切分
|
|
|
|
|
fmt.Printf("%#v\n", lineSlice)
|
2024-07-02 21:48:33 +08:00
|
|
|
|
var structName string
|
2024-07-02 18:19:18 +08:00
|
|
|
|
//2.一行一行的读取数据
|
|
|
|
|
for idx, line := range lineSlice {
|
|
|
|
|
//2.1如果是注释,就跳过
|
|
|
|
|
line = strings.TrimSpace(line)
|
2024-07-02 21:48:33 +08:00
|
|
|
|
//校验:跳过空行
|
|
|
|
|
if len(line) == 0 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2024-07-02 18:19:18 +08:00
|
|
|
|
if strings.HasPrefix(line, ";") || strings.HasPrefix(line, "#") {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
//2.2如果是[开头的,就表示节(section)
|
|
|
|
|
if strings.HasPrefix(line, "[") {
|
|
|
|
|
//校验1 首尾的[]都需要存在
|
|
|
|
|
if line[0] != '[' || line[len(line)-1] != ']' {
|
|
|
|
|
err = fmt.Errorf("line:%d syntax error", idx+1)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
//结之间能取到的内容,比如redis或者mysql这个字符串
|
|
|
|
|
sectionName := strings.TrimSpace(line[1 : len(line)-1])
|
|
|
|
|
//校验2 []之间应该有内容
|
|
|
|
|
if len(sectionName) == 0 { //切片:左包含右不包含
|
|
|
|
|
err = fmt.Errorf("line:%d syntax error", idx+1)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
//根据字符串sectionName到data中根据反射找到结构体
|
|
|
|
|
for i := 0; i < t.Elem().NumField(); i++ {
|
|
|
|
|
field := t.Elem().Field(i)
|
|
|
|
|
if field.Tag.Get("ini") == sectionName {
|
|
|
|
|
//找到对应的嵌套结构体
|
2024-07-02 21:48:33 +08:00
|
|
|
|
structName = field.Name
|
|
|
|
|
fmt.Printf("找到%s对应的嵌套结构体%s\n", sectionName, structName)
|
2024-07-02 18:19:18 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
//2.3如果不是[,就是=分割的键值对
|
2024-07-02 21:48:33 +08:00
|
|
|
|
//校验:不能不存在等号或者以等号开头
|
|
|
|
|
if strings.Index(line, "=") == -1 || strings.HasPrefix(line, "=") {
|
|
|
|
|
err = fmt.Errorf("line:%d syntax error", idx+1)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
//1.以等号分割这一行,等号左边是key,等号右边是value
|
|
|
|
|
|
|
|
|
|
//2.根据structName去data里把对应的嵌套结构体取出
|
|
|
|
|
subValue := v.Elem().FieldByName(structName)
|
|
|
|
|
subType := subValue.Type()
|
|
|
|
|
if subValue.Kind() != reflect.Struct {
|
|
|
|
|
err = fmt.Errorf("field:%s is not struct", structName)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
//切分line这一行,左边是key 右边是value
|
|
|
|
|
key := strings.Split(line, "=")[0]
|
|
|
|
|
value := strings.Split(line, "=")[1]
|
|
|
|
|
|
|
|
|
|
//3.遍历嵌套结构体的每一个字段,判断tag是不是等于key,如果等于key,给这个字段赋值
|
|
|
|
|
|
|
|
|
|
var fieldName string
|
|
|
|
|
for i := 0; i < subType.NumField(); i++ {
|
|
|
|
|
field := subType.Field(i)
|
|
|
|
|
if field.Tag.Get("ini") == key {
|
|
|
|
|
fieldName = field.Name
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//根据fieldName取出 这个字段,对其赋值
|
|
|
|
|
fieldObj := subValue.FieldByName(fieldName)
|
|
|
|
|
fmt.Println(fieldName, fieldObj.Type().Kind())
|
|
|
|
|
switch fieldObj.Type().Kind() {
|
|
|
|
|
case reflect.String:
|
|
|
|
|
fieldObj.SetString(value)
|
|
|
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
|
|
|
valueInt, err := strconv.ParseInt(value, 10, 64)
|
|
|
|
|
if err != nil {
|
|
|
|
|
err = fmt.Errorf("line:%d value:%s error", idx+1, value)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
fieldObj.SetInt(valueInt)
|
|
|
|
|
case reflect.Bool:
|
|
|
|
|
valueBool, err := strconv.ParseBool(value)
|
|
|
|
|
if err != nil {
|
|
|
|
|
err = fmt.Errorf("line:%d value:%s error", idx+1, value)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
fieldObj.SetBool(valueBool)
|
|
|
|
|
}
|
2024-07-02 18:19:18 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-02 21:48:33 +08:00
|
|
|
|
return
|
2024-07-02 18:19:18 +08:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
|
var cfg Config
|
|
|
|
|
err := Loadini("./ini_unmarshal/config.ini", &cfg)
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println("load ini error:", err)
|
|
|
|
|
return
|
|
|
|
|
}
|
2024-07-02 21:48:33 +08:00
|
|
|
|
fmt.Printf("%#v", cfg)
|
2024-07-02 18:19:18 +08:00
|
|
|
|
}
|