csv_loader.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. package serverproto
  2. import (
  3. "encoding/csv"
  4. "errors"
  5. "fmt"
  6. "os"
  7. "reflect"
  8. "strconv"
  9. "strings"
  10. )
  11. ////https://github.com/gocarina/gocsv
  12. //配置表集合
  13. func loadCsvCfg(fileName string, cfg interface{}) {
  14. file, err := os.OpenFile(fileName, os.O_RDONLY, os.ModePerm)
  15. if err != nil {
  16. panic(err)
  17. }
  18. defer file.Close()
  19. csvReader := csv.NewReader(file)
  20. if csvReader == nil {
  21. panic(errors.New(fmt.Sprintf("%v:csv reader nil file", fileName)))
  22. }
  23. err = csvUnmarshal(csvReader, cfg)
  24. if err != nil {
  25. panic(errors.New(fmt.Sprintf("%v:%v", fileName, err)))
  26. }
  27. csvReader = nil
  28. }
  29. func csvUnmarshal(r *csv.Reader, cfg interface{}) error {
  30. cfgValue := reflect.ValueOf(cfg)
  31. if cfgValue.Kind() == reflect.Ptr {
  32. cfgValue = cfgValue.Elem()
  33. }
  34. cfgValueType := cfgValue.Type()
  35. //配置文件类型判断
  36. if cfgValueType.Kind() != reflect.Slice &&
  37. cfgValueType.Kind() != reflect.Chan &&
  38. cfgValueType.Kind() != reflect.Array {
  39. //return fmt.Errorf("cfg type error:%v\n",cfg)
  40. }
  41. csvRows, err := r.ReadAll()
  42. if err != nil {
  43. return err
  44. }
  45. csvRowsNum := len(csvRows)
  46. if csvRowsNum == 0 {
  47. return errors.New("empty csv file!")
  48. }
  49. //判断容量
  50. cfgPtr := &cfgValue
  51. switch cfgPtr.Kind() {
  52. case reflect.Array:
  53. if cfgPtr.Len() < csvRowsNum-1 {
  54. return fmt.Errorf("capacity problem")
  55. }
  56. case reflect.Slice:
  57. if !cfgPtr.CanAddr() && cfgPtr.Len() < csvRowsNum-3 {
  58. return fmt.Errorf("capacity problem")
  59. } else if cfgPtr.CanAddr() && cfgPtr.Len() < csvRowsNum-3 {
  60. cfgPtr.Set(reflect.MakeSlice(cfgPtr.Type(), csvRowsNum-3, csvRowsNum-3))
  61. }
  62. }
  63. stInfo := getStructInfo(cfgValueType.Elem())
  64. if len(stInfo.Fields) <= 0 {
  65. return errors.New("fields empty")
  66. }
  67. csvHeaders := csvRows[1]
  68. csvData := csvRows[3:]
  69. //数据下标对应
  70. csvHeadersLabels := make(map[int]*fieldInfo, len(stInfo.Fields)) //[pos, fieldInfo]
  71. headerMap := map[string]int{} // [name,fieldPos]
  72. for i, csvHeader := range csvHeaders {
  73. currentHeaderPos := headerMap[csvHeader]
  74. if info := getFieldPos(csvHeader, stInfo, currentHeaderPos); info != nil {
  75. info.index = i
  76. csvHeadersLabels[i] = info
  77. }
  78. }
  79. for i, row := range csvData {
  80. var cfgTemp reflect.Value
  81. if cfgValueType.Elem().Kind() == reflect.Ptr {
  82. cfgTemp = reflect.New(cfgValueType.Elem().Elem())
  83. } else {
  84. cfgTemp = reflect.New(cfgValueType.Elem())
  85. }
  86. for j, colData := range row {
  87. if info, ok := csvHeadersLabels[j]; ok {
  88. elm := cfgTemp.Elem()
  89. setFieldData(&elm, colData, info)
  90. }
  91. }
  92. cfgValue.Index(i).Set(cfgTemp)
  93. }
  94. headerMap = nil
  95. csvHeadersLabels = nil
  96. csvHeaders = nil
  97. csvRows = nil
  98. return nil
  99. }
  100. type structInfo struct {
  101. Fields []fieldInfo
  102. }
  103. type fieldInfo struct {
  104. keys string
  105. empty bool
  106. index int
  107. }
  108. func getStructInfo(stType reflect.Type) *structInfo {
  109. if stType.Kind() == reflect.Ptr {
  110. stType = stType.Elem()
  111. }
  112. fieldList := getFieldInfo(stType, []int{})
  113. return &structInfo{
  114. Fields: fieldList,
  115. }
  116. }
  117. func getFieldInfo(stType reflect.Type, index []int) []fieldInfo {
  118. fieldNum := stType.NumField()
  119. fieldList := make([]fieldInfo, 0, fieldNum)
  120. for i := 0; i < fieldNum; i++ {
  121. field := stType.Field(i)
  122. if field.PkgPath != "" {
  123. continue
  124. }
  125. info := fieldInfo{}
  126. info.keys = field.Tag.Get("csv")
  127. fieldList = append(fieldList, info)
  128. }
  129. return fieldList
  130. }
  131. func getFieldPos(header string, stInfo *structInfo, currenPos int) *fieldInfo {
  132. for _, f := range stInfo.Fields {
  133. if f.keys == header {
  134. return &f
  135. }
  136. }
  137. return nil
  138. }
  139. func setFieldData(value *reflect.Value, data string, field *fieldInfo) {
  140. v := (*value).FieldByIndex([]int{field.index})
  141. if v.Kind() == reflect.Ptr {
  142. if v.IsNil() {
  143. v.Set(reflect.New(v.Type().Elem()))
  144. }
  145. //获取指针指向的变量,后续才能做赋值操作
  146. v = v.Elem()
  147. }
  148. inValue := reflect.ValueOf(data)
  149. switch v.Interface().(type) {
  150. case string:
  151. v.SetString(data)
  152. case bool:
  153. if strings.EqualFold(strings.ToLower(data), "true") {
  154. v.SetBool(true)
  155. } else if strings.EqualFold(strings.ToLower(data), "false") {
  156. v.SetBool(false)
  157. }
  158. case int, int32, uint32:
  159. s := strings.TrimSpace(inValue.String())
  160. if s == "" {
  161. v.SetInt(0)
  162. }
  163. i, err := strconv.ParseInt(s, 0, 64)
  164. if err == nil {
  165. v.SetInt(i)
  166. }
  167. case float32:
  168. s := strings.TrimSpace(inValue.String())
  169. if s == "" {
  170. v.SetFloat(0)
  171. }
  172. i, err := strconv.ParseFloat(s, 64)
  173. if err == nil {
  174. v.SetFloat(i)
  175. }
  176. case []string:
  177. dataList := strings.Split(data, ";")
  178. v.Set(reflect.ValueOf(dataList))
  179. default:
  180. panic(errors.New("field type error"))
  181. }
  182. }