diff --git a/base/reflect/ini/conf.ini b/base/reflect/ini/conf.ini new file mode 100644 index 0000000..4f5447f --- /dev/null +++ b/base/reflect/ini/conf.ini @@ -0,0 +1,12 @@ +; mysql 数据库配置 +[mysql] +host=127.0.0.1 +port=3306 +user=root +password=12341234 +# redis 配置 +[redis] +host= 127.0.0.1 +port = 6379 +password =12341234 +db=0 \ No newline at end of file diff --git a/base/reflect/ini/main.go b/base/reflect/ini/main.go new file mode 100644 index 0000000..26ca306 --- /dev/null +++ b/base/reflect/ini/main.go @@ -0,0 +1,176 @@ +package main + +import ( + "fmt" + "io/ioutil" + "os" + "reflect" + "regexp" + "strconv" + "strings" +) + +type IniConfig struct { + Mysql MysqlConfig `ini:"mysql"` + Redis RedisConfig `ini:"redis"` +} + +type MysqlConfig struct { + Host string `ini:"host"` + Port int `ini:"port"` + User string `ini:"user"` + Password string `ini:"password"` +} + +type RedisConfig struct { + Host string `ini:"host"` + Port int `ini:"port"` + Password string `ini:"password"` + Db int `ini:"db"` +} + +func loadIni(filePath string, v interface{}) (err error) { + // 传入的 接收值 v 必须为指针类型 因为需要对齐进行赋值操作 + t := reflect.TypeOf(v) + if v == nil || t.Kind() != reflect.Ptr { + return fmt.Errorf("接收者必须为指针类型\n") + } + + el := t.Elem() + if el.Kind() != reflect.Struct { + return fmt.Errorf("接收者必须为一个结构体对象\n") + } + + // 打开文件 + f, err := os.OpenFile(filePath, os.O_RDONLY, 0644) + if err != nil { + return err + } + + // 读取整个文件 + b, _ := ioutil.ReadAll(f) + // 释放文件占用 + _ = f.Close() + + // ini 文件中 + // ; 开头的为注释 + // [xxx] 为节 + // key=value 为键值对 + + // 读取文件 + conf := string(b) + // 替换换行符 \r\n 为 \n + conf = strings.Replace(conf, "\r\n", "\n", -1) + // 根据换行符 \n 分割行 + confSplit := strings.Split(conf, "\n") + //fmt.Printf("%#v\n", confSplit) + + var curSection string + for _, line := range confSplit { + // 去除 首尾 空格符 + trimReg, _ := regexp.Compile("\\s") + line = trimReg.ReplaceAllLiteralString(line, "") + + // 如果是以 ; 或 # 开头 的 视为注释 直接跳过 + annotationReg, _ := regexp.Compile("^[;|#]") + if annotationReg.MatchString(line) { + continue + } + + sectionReg, _ := regexp.Compile("^\\[(.*)]$") + if sectionReg.MatchString(line) { + sectionMatch := sectionReg.FindAllStringSubmatch(line, 1) + if len(sectionMatch) < 1 { + return fmt.Errorf("无效的 节 %s\n", line) + } + if len(sectionMatch[0]) < 2 { + return fmt.Errorf("无效的 节 %s\n", line) + } + + section := sectionMatch[0][1] + //fmt.Printf("节: %s\n", line) + + value := reflect.ValueOf(v).Elem() + for i := 0; i < el.NumField(); i++ { + field := el.Field(i) + if field.Tag.Get("ini") == section { + item := value.FieldByName(field.Name) + if item.Kind() == reflect.Ptr { + return fmt.Errorf("接收者 %s 不能为指针\n", section) + } + //if item.Kind() == reflect.Struct { + // fmt.Printf("%s 为结构体\n", section) + //} + + curSection = field.Name + break + } + } + continue + } + + if strings.EqualFold(curSection, "") { + continue + } + + keyValueReg, _ := regexp.Compile("^(.*)=(.*)$") + if keyValueReg.MatchString(line) { + keyValueMatch := keyValueReg.FindAllStringSubmatch(line, -1) + if len(keyValueMatch) < 1 { + //fmt.Println("未找到 匹配的 键值对") + continue + } + keyValueSubMatch := keyValueMatch[0] + if len(keyValueSubMatch) < 3 { + //fmt.Println("未找到 匹配的 键值对") + continue + } + k := keyValueSubMatch[1] + val := keyValueSubMatch[2] + //fmt.Printf("键值对: k: %#v => v: %#v\n", k, val) + + sectionReflectType, _ := reflect.TypeOf(v).Elem().FieldByName(curSection) + sectionType := sectionReflectType.Type + sectionVal := reflect.ValueOf(v).Elem().FieldByName(curSection) + + if sectionVal.Kind() != reflect.Struct { + return fmt.Errorf("section 接收者 需为 struct 类型\n") + } + + for i := 0; i < sectionVal.NumField(); i++ { + selectionKey := sectionType.Field(i).Tag.Get("ini") + + if strings.EqualFold(selectionKey, k) { + //fmt.Println(selectionKey, sectionVal.Field(i).Kind()) + switch sectionVal.Field(i).Kind() { + case reflect.Int: + intVal, err := strconv.Atoi(val) + if err != nil { + return err + } + sectionVal.Field(i).SetInt(int64(intVal)) + case reflect.String: + sectionVal.Field(i).SetString(val) + } + break + } + } + + continue + } + + fmt.Println(line) + } + + return +} + +func main() { + config := new(IniConfig) + err := loadIni("./base/reflect/ini/conf.ini", config) + if err != nil { + fmt.Println(err) + } + + fmt.Printf("%#v\n", config) +}