:::success
- 任务:解析如下配置文件
- 序列化:将结构体序列化为配置文件数据并保存到硬盘
- 反序列化:将配置文件内容反序列化到程序的结构体
- 配置文件有server和mysql相关配置
:::
#this is comment;this a comment;[]表示一个section[server]ip = 10.238.2.2port = 8080[mysql]username = rootpasswd = admindatabase = testhost = 192.168.10.10port = 8000timeout = 1.2
代码地址:https://github.com/lu569368/Practise_reflex.git
#this is comment;this a comment;[]表示一个section[server]ip = 10.238.2.2port = 8080[mysql]username = rootpasswd = admindatabase = testhost = 192.168.10.10port = 8000timeout = 1.2
package mainimport ("fmt""io/ioutil""reflect""strconv""strings")// 序列化和反序列化// 序列化数据到指定的文件func MarshalFile(filename string, data interface{}) (err error) {// 1.数据的序列化result, err := Marshal(data)if err != nil {return}// 2.将序列化好的数据,写出到filenamereturn ioutil.WriteFile(filename, result, 0666)}// 序列化的方法// 传入的结构体 ——> []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)// 取值labelVal := valueInfo.Field(i)fieldType := labelField.Type// 判断字段类型if fieldType.Kind() != reflect.Struct {continue}// 拼的是[server]和[mysql]// 获取个tagtagVal := labelField.Tag.Get("ini")if len(tagVal) == 0 {tagVal = labelField.Name}label := fmt.Sprintf("\n[%s]\n", tagVal)conf = append(conf, label)// 拼 k-vfor j := 0; j < fieldType.NumField(); j++ {// 这里取到的是大写keyField := fieldType.Field(j)// 取tagfieldTagVal := keyField.Tag.Get("ini")if len(fieldTagVal) == 0 {fieldTagVal = keyField.Name}// 取值valField := labelVal.Field(j)// Interface()取真正对应的值item := fmt.Sprintf("%s=%v\n", fieldTagVal, valField.Interface())conf = append(conf, item)}}// 遍历切片转类型for _, val := range conf {byteVal := []byte(val)result = append(result, byteVal...)}return}// 文件读取数据,做反序列化func UnMarshalFile(filename string, result interface{}) (err error) {// 1.文件读取data, err := ioutil.ReadFile(filename)if err != nil {return}// 2.进行反序列化return UnMarshal(data, result)}// 反序列化// []byte ---- > 结构体func UnMarshal(data []byte, result interface{}) (err error) {// 先判断是否是指针typeInfo := reflect.TypeOf(result)if typeInfo.Kind() != reflect.Ptr {return}// 判断是否是结构体if typeInfo.Elem().Kind() != reflect.Struct {return}// 转类型,按行切割lineArr := strings.Split(string(data), "\n")// 定义全局标签名 也就是server和mysqlvar myFiledName stringfor _, line := range lineArr {// 各种严谨判断line = strings.TrimSpace(line)// 处理文档中有注释的情况if len(line) == 0 || line[0] == ';' || line[0] == '#' {continue}// 按照括号去判断if line[0] == '[' {// 按照大标签去处理myFiledName, err = myLabel(line, typeInfo.Elem())if err != nil {return}continue}// 按照正常数据处理err = myField(myFiledName, line, result)if err != nil {return}}return}// 处理大标签func myLabel(line string, typeInfo reflect.Type) (fieldName string, err error) {// 去字符串头和尾labelName := line[1 : len(line)-1]// 循环去结构体找tag,对应上才能解析for i := 0; i < typeInfo.NumField(); i++ {field := typeInfo.Field(i)tagValue := field.Tag.Get("ini")// 判断tagif labelName == tagValue {fieldName = field.Namebreak}}return}// 解析属性// 参数:大标签名,行数据,对象func myField(fieldName string, line string, result interface{}) (err error) {fmt.Println(line)key := strings.TrimSpace(line[0:strings.Index(line, "=")])val := strings.TrimSpace(line[strings.Index(line, "=")+1:])// 解析到结构体//resultType := reflect.TypeOf(result)resultValue := reflect.ValueOf(result)// 拿到字段值,这里直接设置不知道类型labelValue := resultValue.Elem().FieldByName(fieldName)// 拿到该字段类型fmt.Println(labelValue)labelType := labelValue.Type()// 第一次进来应该是server// 存放取到的字段名var keyName string// 遍历server结构体的所有字段for i := 0; i < labelType.NumField(); i++ {// 获取结构体字段field := labelType.Field(i)tagVal := field.Tag.Get("ini")if tagVal == key {keyName = field.Namebreak}}// 给字段赋值// 取字段值filedValue := labelValue.FieldByName(keyName)// 修改值switch filedValue.Type().Kind() {case reflect.String:filedValue.SetString(val)case reflect.Int:i, err2 := strconv.ParseInt(val, 10, 64)if err2 != nil {fmt.Println(err2)return}filedValue.SetInt(i)case reflect.Uint:i, err := strconv.ParseUint(val, 10, 64)if err != nil {fmt.Println(err)return err}filedValue.SetUint(i)case reflect.Float32:f, _ := strconv.ParseFloat(val, 64)//if err != nil {// fmt.Println(err)// return//}filedValue.SetFloat(f)}return}
package mainimport ("fmt""io/ioutil")// 解析文件func parseFile(filename string) {data, err := ioutil.ReadFile(filename)if err != nil {return}var conf Configerr = UnMarshal(data, &conf)if err != nil {return}fmt.Printf("反序列化成功 conf: %#v\n port: %#v\n", conf, conf.ServerConf.Port)}func parseFile2(filename string) {// 有一些假数据var conf Configconf.ServerConf.Ip="127.0.0.1"conf.ServerConf.Port=8000conf.MysqlConf.Port=9000err := MarshalFile(filename,conf)if err != nil{return}}func main() {//parseFile("D:/config.ini")parseFile2("D:/my2.ini")}
package maintype ServerConfig struct {Ip string `ini:"ip"`Port int `ini:"port"`}type MysqlConfig struct {Username string `ini:"username"`Passwd string `ini:"passwd"`Database string `ini:"database"`Host string `ini:"host"`Port int `ini:"port"`Timeout float32 `ini:"timeout"`}// 总的type Config struct {ServerConf ServerConfig `ini:"server"`MysqlConf MysqlConfig `ini:"mysql"`}
