conf.ini
config.ini
;test
#test
[server]
ip=192.168.0.100
port = 8080
[ mysql]
username=root
password = abc-123
database=test
host=192.168.0.1.1
port=3306
ini_config.go //实现代码
package config
import (
"errors"
"fmt"
"io/ioutil"
"os"
"reflect"
"strconv"
"strings"
)
//序列化成配置文件
func MarshalFile(data interface{}, filename string) (err error) {
result, err := Marshal(data)
if err != nil {
return
}
err = ioutil.WriteFile(filename, result, os.ModePerm)
return
}
//序列化配置
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 confData []string
valueInfo := reflect.ValueOf(data)
for i := 0; i < typeInfo.NumField(); i++ {
sectionField := typeInfo.Field(i)
sectionValue := valueInfo.Field(i)
fieldType := sectionField.Type
if fieldType.Kind() != reflect.Struct {
continue
}
tagValue := sectionField.Tag.Get("ini")
if len(tagValue) == 0 {
tagValue = sectionField.Name
}
section := fmt.Sprintf("\n[%s]\n", tagValue)
confData = append(confData, section)
//fmt.Println(confData)
for j := 0; j < sectionField.Type.NumField(); j++ {
keyField := sectionField.Type.Field(j)
fieldTagVal := keyField.Tag.Get("ini")
if len(fieldTagVal) == 0 {
fieldTagVal = keyField.Name
}
valueField := sectionValue.Field(j)
item := fmt.Sprintf("%s=%v\n", fieldTagVal, valueField.Interface())
confData = append(confData, item)
}
}
for _, value := range confData {
result = append(result, []byte(value)...)
}
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) {
//获取类型信息
typeInfo := reflect.TypeOf(result)
if typeInfo.Kind() != reflect.Ptr {
err = errors.New("please pass point address")
return
}
//判断指向变量的类型
typeStruct := typeInfo.Elem()
if typeStruct.Kind() != reflect.Struct {
err = errors.New("please pass strut data")
return
}
//遍历配置文件
lineArr := strings.Split(string(data), "\n")
var lastFieldName string
for index, value := range lineArr {
line := strings.TrimSpace(value)
if len(line) == 0 { //判断是否为空行,如果是空行就跳过
continue
}
//如果是注释就跳过
if line[0] == ';' || line[0] == '#' {
continue
}
if line[0] == '[' {
lastFieldName, err = ParseSection(line, typeStruct, index)
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
}
}
//var m map[string] string
return
}
func parseItem(lastFieldName string, line string, result interface{}) (err error) {
//判断节点下的选项
subIndex := strings.Index(line, "=")
if subIndex == -1 {
err = fmt.Errorf("syntax error,line:%s", line)
return
}
key := strings.TrimSpace(line[0:subIndex])
val := strings.TrimSpace(line[subIndex+1:])
if len(key) == 0 {
err = fmt.Errorf("syntax 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
}
//fmt.Println(keyFieldName,val)
fieldValue := sectionValue.FieldByName(keyFieldName)
if fieldValue == reflect.ValueOf(nil) {
return
}
switch fieldKind := fieldValue.Type().Kind(); fieldKind {
case reflect.String:
fieldValue.SetString(val)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
intVal, errRet := strconv.ParseInt(val, 10, 64)
if errRet != nil {
err = errRet
return
}
fieldValue.SetInt(intVal)
case reflect.Uint, reflect.Uint8, reflect.Uint16, 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 {
err = errRet
return
}
fieldValue.SetFloat(floatVal)
default:
err = fmt.Errorf("unsupport type:%v", fieldKind)
return
}
return
}
func ParseSection(line string, typeInfo2 reflect.Type, index int) (fieldName string, err error) {
//判断节点的合法性
if line[0] == '[' && len(line) <= 2 {
err = fmt.Errorf("synatax error,inalid section:%s,line:%d", line, index+1)
return
}
if line[0] == '[' && line[len(line)-1] != ']' {
err = fmt.Errorf("synatax error,inalid section:%s,line:%d", line, index+1)
return
}
if line[0] == '[' && line[len(line)-1] == ']' {
sectionName := strings.TrimSpace(line[1 : len(line)-1])
if len(sectionName) == 0 {
err = fmt.Errorf("synatax error,inalid section:%s,line:%d", line, index+1)
return
}
for i := 0; i < typeInfo2.NumField(); i++ {
field := typeInfo2.Field(i)
tagValue := field.Tag.Get("ini")
if tagValue == sectionName {
fieldName = field.Name
break
}
}
}
return
}
//测试用例
ini_config_test.go
package config
import (
"fmt"
"io/ioutil"
"testing"
)
type Config struct{
ServerConf ServerConfig `ini:"server"`
MysqlConf MysqlConfig `ini:"mysql"`
}
type ServerConfig struct {
IP string `ini:"ip"`
Port int `ini:"port"`
}
type MysqlConfig struct {
Username string `ini:"username"`
Password string `ini:"password"`
Database string `ini:"database"`
Host string `ini:"host"`
Port int `ini:"port"`
}
func TestIniConfig(t *testing.T){
//fmt.Println("hello")
//t.Error("run failed")
data,err := ioutil.ReadFile("config.ini")
if err != nil {
t.Errorf("read ini config file failed:%v\n",err)
}
//fmt.Printf("ini context:%s\n",string(data))
var conf Config
err = UnMarshal(data,&conf)
if err != nil {
t.Errorf("UnMarshal failed:%v\n",err)
return
}
t.Logf("unmarshal sucess,conf:%#v\n",conf)
fmt.Printf("\n------------------------------------\n")
data,err = Marshal(conf)
if err != nil {
t.Errorf("marshal faield:%v\n",err)
return
}
t.Logf("marshal sucess:%v\n",string(data))
fmt.Printf("\n------------------------------------\n")
/*err = MarshalFile(conf,"./test.ini")
if err != nil {
t.Logf("write file failed:%v\n",err)
return
}*/
//UnMarshalFile
fmt.Printf("\n------------------------------------\n")
var conf2 Config
err = UnMarshalFile("test.ini",&conf2)
if err !=nil {
t.Errorf("unmarshalFile failed:%v\n",err)
return
}
t.Logf("unmarshalFile sucess:%#v\n",conf2)
}
使用反射实现序列化与反序列化
最新推荐文章于 2022-11-30 12:26:08 发布