:::success

    • 任务:解析如下配置文件
      • 序列化:将结构体序列化为配置文件数据并保存到硬盘
      • 反序列化:将配置文件内容反序列化到程序的结构体
    • 配置文件有server和mysql相关配置

    :::

    1. #this is comment
    2. ;this a comment
    3. ;[]表示一个section
    4. [server]
    5. ip = 10.238.2.2
    6. port = 8080
    7. [mysql]
    8. username = root
    9. passwd = admin
    10. database = test
    11. host = 192.168.10.10
    12. port = 8000
    13. timeout = 1.2

    代码地址:https://github.com/lu569368/Practise_reflex.git

    1. #this is comment
    2. ;this a comment
    3. ;[]表示一个section
    4. [server]
    5. ip = 10.238.2.2
    6. port = 8080
    7. [mysql]
    8. username = root
    9. passwd = admin
    10. database = test
    11. host = 192.168.10.10
    12. port = 8000
    13. timeout = 1.2
    1. package main
    2. import (
    3. "fmt"
    4. "io/ioutil"
    5. "reflect"
    6. "strconv"
    7. "strings"
    8. )
    9. // 序列化和反序列化
    10. // 序列化数据到指定的文件
    11. func MarshalFile(filename string, data interface{}) (err error) {
    12. // 1.数据的序列化
    13. result, err := Marshal(data)
    14. if err != nil {
    15. return
    16. }
    17. // 2.将序列化好的数据,写出到filename
    18. return ioutil.WriteFile(filename, result, 0666)
    19. }
    20. // 序列化的方法
    21. // 传入的结构体 ——> []byte
    22. // 基本思路:反射解析出传入的数据,转字节切片
    23. func Marshal(data interface{}) (result []byte, err error) {
    24. // 获取下类型
    25. typeInfo := reflect.TypeOf(data)
    26. valueInfo := reflect.ValueOf(data)
    27. // 判断类型
    28. if typeInfo.Kind() != reflect.Struct {
    29. return
    30. }
    31. var conf [] string
    32. // 获取所有字段去处理
    33. for i := 0; i < typeInfo.NumField(); i++ {
    34. // 取字段
    35. labelField := typeInfo.Field(i)
    36. // 取值
    37. labelVal := valueInfo.Field(i)
    38. fieldType := labelField.Type
    39. // 判断字段类型
    40. if fieldType.Kind() != reflect.Struct {
    41. continue
    42. }
    43. // 拼的是[server]和[mysql]
    44. // 获取个tag
    45. tagVal := labelField.Tag.Get("ini")
    46. if len(tagVal) == 0 {
    47. tagVal = labelField.Name
    48. }
    49. label := fmt.Sprintf("\n[%s]\n", tagVal)
    50. conf = append(conf, label)
    51. // 拼 k-v
    52. for j := 0; j < fieldType.NumField(); j++ {
    53. // 这里取到的是大写
    54. keyField := fieldType.Field(j)
    55. // 取tag
    56. fieldTagVal := keyField.Tag.Get("ini")
    57. if len(fieldTagVal) == 0 {
    58. fieldTagVal = keyField.Name
    59. }
    60. // 取值
    61. valField := labelVal.Field(j)
    62. // Interface()取真正对应的值
    63. item := fmt.Sprintf("%s=%v\n", fieldTagVal, valField.Interface())
    64. conf = append(conf, item)
    65. }
    66. }
    67. // 遍历切片转类型
    68. for _, val := range conf {
    69. byteVal := []byte(val)
    70. result = append(result, byteVal...)
    71. }
    72. return
    73. }
    74. // 文件读取数据,做反序列化
    75. func UnMarshalFile(filename string, result interface{}) (err error) {
    76. // 1.文件读取
    77. data, err := ioutil.ReadFile(filename)
    78. if err != nil {
    79. return
    80. }
    81. // 2.进行反序列化
    82. return UnMarshal(data, result)
    83. }
    84. // 反序列化
    85. // []byte ---- > 结构体
    86. func UnMarshal(data []byte, result interface{}) (err error) {
    87. // 先判断是否是指针
    88. typeInfo := reflect.TypeOf(result)
    89. if typeInfo.Kind() != reflect.Ptr {
    90. return
    91. }
    92. // 判断是否是结构体
    93. if typeInfo.Elem().Kind() != reflect.Struct {
    94. return
    95. }
    96. // 转类型,按行切割
    97. lineArr := strings.Split(string(data), "\n")
    98. // 定义全局标签名 也就是server和mysql
    99. var myFiledName string
    100. for _, line := range lineArr {
    101. // 各种严谨判断
    102. line = strings.TrimSpace(line)
    103. // 处理文档中有注释的情况
    104. if len(line) == 0 || line[0] == ';' || line[0] == '#' {
    105. continue
    106. }
    107. // 按照括号去判断
    108. if line[0] == '[' {
    109. // 按照大标签去处理
    110. myFiledName, err = myLabel(line, typeInfo.Elem())
    111. if err != nil {
    112. return
    113. }
    114. continue
    115. }
    116. // 按照正常数据处理
    117. err = myField(myFiledName, line, result)
    118. if err != nil {
    119. return
    120. }
    121. }
    122. return
    123. }
    124. // 处理大标签
    125. func myLabel(line string, typeInfo reflect.Type) (fieldName string, err error) {
    126. // 去字符串头和尾
    127. labelName := line[1 : len(line)-1]
    128. // 循环去结构体找tag,对应上才能解析
    129. for i := 0; i < typeInfo.NumField(); i++ {
    130. field := typeInfo.Field(i)
    131. tagValue := field.Tag.Get("ini")
    132. // 判断tag
    133. if labelName == tagValue {
    134. fieldName = field.Name
    135. break
    136. }
    137. }
    138. return
    139. }
    140. // 解析属性
    141. // 参数:大标签名,行数据,对象
    142. func myField(fieldName string, line string, result interface{}) (err error) {
    143. fmt.Println(line)
    144. key := strings.TrimSpace(line[0:strings.Index(line, "=")])
    145. val := strings.TrimSpace(line[strings.Index(line, "=")+1:])
    146. // 解析到结构体
    147. //resultType := reflect.TypeOf(result)
    148. resultValue := reflect.ValueOf(result)
    149. // 拿到字段值,这里直接设置不知道类型
    150. labelValue := resultValue.Elem().FieldByName(fieldName)
    151. // 拿到该字段类型
    152. fmt.Println(labelValue)
    153. labelType := labelValue.Type()
    154. // 第一次进来应该是server
    155. // 存放取到的字段名
    156. var keyName string
    157. // 遍历server结构体的所有字段
    158. for i := 0; i < labelType.NumField(); i++ {
    159. // 获取结构体字段
    160. field := labelType.Field(i)
    161. tagVal := field.Tag.Get("ini")
    162. if tagVal == key {
    163. keyName = field.Name
    164. break
    165. }
    166. }
    167. // 给字段赋值
    168. // 取字段值
    169. filedValue := labelValue.FieldByName(keyName)
    170. // 修改值
    171. switch filedValue.Type().Kind() {
    172. case reflect.String:
    173. filedValue.SetString(val)
    174. case reflect.Int:
    175. i, err2 := strconv.ParseInt(val, 10, 64)
    176. if err2 != nil {
    177. fmt.Println(err2)
    178. return
    179. }
    180. filedValue.SetInt(i)
    181. case reflect.Uint:
    182. i, err := strconv.ParseUint(val, 10, 64)
    183. if err != nil {
    184. fmt.Println(err)
    185. return err
    186. }
    187. filedValue.SetUint(i)
    188. case reflect.Float32:
    189. f, _ := strconv.ParseFloat(val, 64)
    190. //if err != nil {
    191. // fmt.Println(err)
    192. // return
    193. //}
    194. filedValue.SetFloat(f)
    195. }
    196. return
    197. }
    1. package main
    2. import (
    3. "fmt"
    4. "io/ioutil"
    5. )
    6. // 解析文件
    7. func parseFile(filename string) {
    8. data, err := ioutil.ReadFile(filename)
    9. if err != nil {
    10. return
    11. }
    12. var conf Config
    13. err = UnMarshal(data, &conf)
    14. if err != nil {
    15. return
    16. }
    17. fmt.Printf("反序列化成功 conf: %#v\n port: %#v\n", conf, conf.ServerConf.Port)
    18. }
    19. func parseFile2(filename string) {
    20. // 有一些假数据
    21. var conf Config
    22. conf.ServerConf.Ip="127.0.0.1"
    23. conf.ServerConf.Port=8000
    24. conf.MysqlConf.Port=9000
    25. err := MarshalFile(filename,conf)
    26. if err != nil{
    27. return
    28. }
    29. }
    30. func main() {
    31. //parseFile("D:/config.ini")
    32. parseFile2("D:/my2.ini")
    33. }
    1. package main
    2. type ServerConfig struct {
    3. Ip string `ini:"ip"`
    4. Port int `ini:"port"`
    5. }
    6. type MysqlConfig struct {
    7. Username string `ini:"username"`
    8. Passwd string `ini:"passwd"`
    9. Database string `ini:"database"`
    10. Host string `ini:"host"`
    11. Port int `ini:"port"`
    12. Timeout float32 `ini:"timeout"`
    13. }
    14. // 总的
    15. type Config struct {
    16. ServerConf ServerConfig `ini:"server"`
    17. MysqlConf MysqlConfig `ini:"mysql"`
    18. }