golang 配置库项目
golang 配置库项目.反射 在运行时动态的获取一个变量的类型信息和值信息
A. 序列化和反序列化,比如json, protobuf等各种数据协议
B. 各种数据库的ORM, 比如gorm,sqlx等数据库中间件
C. 配置文件解析相关的库, 比如yaml、ini等
#this is comment;this a comment;[]表示一个sectionip=10.238.2.2port = 8080username =rootpasswd = rootdatabase=testhost=192.168.1.1port=3838 timeout=1.2ini_config.go
package iniconfigimport ( "errors" "fmt" "io/ioutil" "reflect" "strconv" "strings")func MarshalFile(filename string, data interface{}) (err error) { result, err := Marshal(data) if err != nil { return } return ioutil.WriteFile(filename, result, 0755)}func Marshal(data interface{}) (result []byte, err error) { typeInfo := reflect.TypeOf(data) if typeInfo.Kind() != reflect.Struct { err = errors.New("please pass struct") return } var conf []string valueInfo := reflect.ValueOf(data) for i := 0; i < typeInfo.NumField(); i++ { sectionField := typeInfo.Field(i) sectionVal := valueInfo.Field(i) fieldType := sectionField.Type if fieldType.Kind() != reflect.Struct { continue } tagVal := sectionField.Tag.Get("ini") if len(tagVal) == 0 { tagVal = sectionField.Name } section := fmt.Sprintf("\n[%s]\n", tagVal) conf = append(conf, section) for j := 0; j < fieldType.NumField(); j++ { keyField := fieldType.Field(j) fieldTagVal := keyField.Tag.Get("ini") if len(fieldTagVal) == 0 { fieldTagVal = keyField.Name } valField := sectionVal.Field(j) 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) { data, err := ioutil.ReadFile(filename) if err != nil { return } return UnMarshal(data, result)}func UnMarshal(data []byte, result interface{}) (err error) { lineArr := strings.Split(string(data), "\n") typeInfo := reflect.TypeOf(result) if typeInfo.Kind() != reflect.Ptr { err = errors.New("please pass address") return } typeStruct := typeInfo.Elem() if typeStruct.Kind() != reflect.Struct { err = errors.New("please pass struct") return } var lastFieldName string for index, line := range lineArr { line = strings.TrimSpace(line) if len(line) == 0 { continue } //如果是注释,直接忽略 if line == ';' || line == '#' { continue } if line == '[' { lastFieldName, err = parseSection(line, typeStruct) if err != nil { err = fmt.Errorf("%v lineno:%d", err, index+1) return } continue } err = parseItem(lastFieldName, line, result) if err != nil { err = fmt.Errorf("%v lineno:%d", err, index+1) return } } return}func parseItem(lastFieldName string, line string, result interface{}) (err error) { index := strings.Index(line, "=") if index == -1 { err = fmt.Errorf("sytax error, line:%s", line) return } key := strings.TrimSpace(line) val := strings.TrimSpace(line) if len(key) == 0 { err = fmt.Errorf("sytax error, line:%s", line) return } resultValue := reflect.ValueOf(result) sectionValue := resultValue.Elem().FieldByName(lastFieldName) sectionType := sectionValue.Type() if sectionType.Kind() != reflect.Struct { err = fmt.Errorf("field:%s must be struct", lastFieldName) return } keyFieldName := "" for i := 0; i < sectionType.NumField(); i++ { field := sectionType.Field(i) tagVal := field.Tag.Get("ini") if tagVal == key { keyFieldName = field.Name break } } if len(keyFieldName) == 0 { return } fieldValue := sectionValue.FieldByName(keyFieldName) if fieldValue == reflect.ValueOf(nil) { return } switch fieldValue.Type().Kind() { case reflect.String: fieldValue.SetString(val) case reflect.Int8, reflect.Int16, reflect.Int, reflect.Int32, reflect.Int64: intVal, errRet := strconv.ParseInt(val, 10, 64) if errRet != nil { err = errRet return } fieldValue.SetInt(intVal) case reflect.Uint8, reflect.Uint16, reflect.Uint, reflect.Uint32, reflect.Uint64: intVal, errRet := strconv.ParseUint(val, 10, 64) if errRet != nil { err = errRet return } fieldValue.SetUint(intVal) case reflect.Float32, reflect.Float64: floatVal, errRet := strconv.ParseFloat(val, 64) if errRet != nil { return } fieldValue.SetFloat(floatVal) default: err = fmt.Errorf("unsupport type:%v", fieldValue.Type().Kind()) } return}func parseSection(line string, typeInfo reflect.Type) (fieldName string, err error) { if line == '[' && len(line) <= 2 { err = fmt.Errorf("syntax error, invalid section:%s", line) return } if line == '[' && line != ']' { err = fmt.Errorf("syntax error, invalid section:%s", line) return } if line == '[' && line == ']' { sectionName := strings.TrimSpace(line) if len(sectionName) == 0 { err = fmt.Errorf("syntax error, invalid section:%s", line) return } for i := 0; i < typeInfo.NumField(); i++ { field := typeInfo.Field(i) tagValue := field.Tag.Get("ini") if tagValue == sectionName { fieldName = field.Name break } } } return}ini_config_test.go
package iniconfigimport ( "io/ioutil" "testing")type Config struct { ServerConf ServerConfig `ini:"server"` MysqlConfMysqlConfig`ini:"mysql"`}type ServerConfig struct { Ip string `ini:"ip"` Port uint `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"` Timeoutfloat32 `ini:"timeout"`}func TestIniConfig(t *testing.T) { data, err := ioutil.ReadFile("./config.ini") if err != nil { t.Error("read file failed") } var conf Config err = UnMarshal(data, &conf) if err != nil { t.Errorf("unmarshal failed, err:%v", err) return } t.Logf("unmarshal success, conf:%#v, port:%v", conf, conf.ServerConf.Port) confData, err := Marshal(conf) if err != nil { t.Errorf("marshal failed, err:%v", err) } t.Logf("marshal succ, conf:%s", string(confData)) //MarshalFile(conf, "C:/tmp/test.conf")}func TestIniConfigFile(t *testing.T) { filename := "C:/tmp/test.conf" var conf Config conf.ServerConf.Ip = "localhost" conf.ServerConf.Port = 88888 err := MarshalFile(filename, conf) if err != nil { t.Errorf("marshal failed, err:%v", err) return } var conf2 Config err = UnMarshalFile(filename, &conf2) if err != nil { t.Errorf("unmarshal failed, err:%v", err) } t.Logf("unmarshal succ, conf:%#v", conf2)}
页:
[1]