本文参考:
https://github.com/lu569368/Practise_reflex/
ini文件示例:
# 注释 ; 注释 ; 注释 \[redis\] ip = 127.0.0.1 port = 8080 \[mysql\] host = 127.0.0.1 port = 3300 database = test user = root password = 123456 timeout = 30
结构体定义:
type RedisConfig struct { Ip string \`ini:"ip"\` Port int \`ini:"port"\` } type MysqlConfig struct { Host string \`ini:"host"\` Port int \`ini:"port"\` Database string \`ini:"database"\` User string \`ini:"user"\` Password string \`ini:"password"\` Timeout int \`ini:"timeout"\` } type Config struct { RedisConfig RedisConfig \`ini:"redis"\` MysqlConfig MysqlConfig \`ini:"mysql"\` }
解析ini文件代码:
func unMarshalFile(fileName string, result interface{}) (err error) { data, err := ioutil.ReadFile(fileName) if err != nil { return err } err = UnMarshal(data, result) if err != nil { return err } return } func UnMarshal(data \[\]byte, result interface{}) (err error) { //传入的赋值变量必须为指针类型的结构体 typeInfo := reflect.TypeOf(result) if typeInfo.Kind() != reflect.Ptr { return nil } if typeInfo.Elem().Kind() != reflect.Struct { return nil } lineArr := strings.Split(string(data), "\\n") var myFieldName string for _, line := range lineArr { //fmt.Printf("line:%s \\n",line) //注释判断 //去掉2边的空格等 line = strings.TrimSpace(line) //注释和无效字符 if len(line) == 0 || line\[0\] == ';' || line\[0\] == '#' { continue } if line\[0\] == '\[' { //大标签处理 myFieldName, err = myLabel(line, typeInfo.Elem()) if err != nil { return } continue } err = myField(myFieldName, line, result) if err != nil { return } } return } func myLabel(line string, typeInfo reflect.Type) (fieldName string, err error) { //去掉字符串头尾 labelName := line\[1 : len(line)-1\] //fmt.Printf("myLabel \\n") //循环去结构体找tag,对应上才能解析 for i := 0; i < typeInfo.NumField(); i++ { field := typeInfo.Field(i) tagValue := field.Tag.Get("ini") //fmt.Printf("myLabel.filed:%s \\n",field) //fmt.Printf("myLabel.tagValue:%s \\n",tagValue) //判断tag if labelName == tagValue { fieldName = field.Name break } } return } func myField(fieldName string, line string, result interface{}) (err error) { key := strings.TrimSpace(line\[0:strings.Index(line, "=")\]) value := strings.TrimSpace(line\[strings.Index(line, "=")+1:\]) //解析到结构体(config) resultValue := reflect.ValueOf(result) //获取结构体的结构体数据 labelValue := resultValue.Elem().FieldByName(fieldName) //获取到字段类型 labelType := labelValue.Type() var keyName string for i := 0; i < labelType.NumField(); i++ { field := labelType.Field(i) tagVal := field.Tag.Get("ini") if tagVal == key { keyName = field.Name break } } //给字段赋值 //取字段值 fieldValue := labelValue.FieldByName(keyName) switch fieldValue.Type().Kind() { case reflect.String: fieldValue.SetString(value) case reflect.Int: i, err := strconv.ParseInt(value, 10, 64) if err != nil { fmt.Println(err) return err } fieldValue.SetInt(i) case reflect.Uint: i, err := strconv.ParseUint(value, 10, 64) if err != nil { fmt.Println(err) return err } fieldValue.SetUint(i) case reflect.Float32: f, err := strconv.ParseFloat(value, 64) if err != nil { fmt.Println(err) return err } fieldValue.SetFloat(f) } return err }
结构体序列化代码:
func MarshalFile(filename string,data interface{}) (err error){ result,_ := Marshal(data) err = ioutil.WriteFile(filename,result,0666) return err } //反序列思路 //传入结构体->\[\]byte //反射获取数据,转直接切片 func Marshal(data interface{}) (result \[\]byte, err error) { //获取类型 typeInfo := reflect.TypeOf(data) valueInfo := reflect.ValueOf(data) if typeInfo.Kind() != reflect.Struct { return } var conf \[\]string for i := 0; i < typeInfo.NumField(); i++ { //取字段 labelField := typeInfo.Field(i) //取值 labelValue := valueInfo.Field(i) fieldType := labelField.Type //判断字段类型,如果不是struct,说明不对 if fieldType.Kind() != reflect.Struct { continue } tagValue := labelField.Tag.Get("ini") if len(tagValue) == 0 { tagValue = labelField.Name } label := fmt.Sprintf("\\n\[%s\]\\n", tagValue) conf = append(conf, label) for j := 0; j < fieldType.NumField(); j++ { //这里的是大写的字段名 keyField := fieldType.Field(j) //取tag fieldTagValue := keyField.Tag.Get("ini") if len(fieldTagValue) == 0 { fieldTagValue = keyField.Name } //取值 valueField := labelValue.Field(j) item := fmt.Sprintf("%s = %v \\n", fieldTagValue, valueField.Interface()) conf = append(conf, item) } } for _, val := range conf { byteVal := \[\]byte(val) result = append(result, byteVal...) } return }
调用:
package main import "fmt" func main() { var conf Config _ = unMarshalFile("./config.ini", &conf) fmt.Printf("解析文件成功 config:%#v\\n port:%#v\\n", conf, conf.RedisConfig.Port) conf2 := Config{ RedisConfig{Ip: "127.0.0.1", Port: 6379}, MysqlConfig{Host: "127.0.0.1", User: "root", Password: "123456"}, } _ = MarshalFile("1.ini", conf2) fmt.Printf("序列化文件成功\\n") }
输出结果: