ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

golang-reflect实战ini配置文件

2021-09-15 14:35:43  阅读:173  来源: 互联网

标签:reflect string 配置文件 fmt LableFieldName golang ini line strings


config.ini 配置文件

#this is comment
;this a comment
;[]表示一个section
[server]
ip = 192.168.0.1
port = 9000

[mysql]
username = root
passwd = admin
database = test
host = 192.168.10.10
port = 8000
timeout = 1.2
package main

import (
	"fmt"
	"io/ioutil"
	"reflect"
	"strconv"
	"strings"
)
/*
需求就是读取config.ini 配置文件
反序列化对config 这个结构体中

*/
type ServerConf struct {
	Ip string `ini:"ip"`
	Port int `ini:"port"`
}

type MysqlConf struct {
	Username string `ini:"username"`
	Passwd string `ini:"passwd"`
	Database string `ini:"database"`
	Host string `ini:"host"`
	Port int `ini:"port"`
	Timeout float64 `ini:"timeout"`
}

type Config struct {
	Server ServerConf `ini:"server"`
	Mysql MysqlConf  `ini:"mysql"`
}


func Unmarshal(data []byte, v interface{}) (err error) {
	//严谨判断
	rt := reflect.TypeOf(v)
	kind := rt.Kind()
	//判断是不是指针
	if kind != reflect.Ptr {
		panic("类型错误必须传入指针")
		return err
	}
	//判断是不是结构体
	if rt.Elem().Kind() != reflect.Struct{
		panic("类型错误必须是结构体指针")
		return err
	}

	//data就是我们读取的配置数据
	//按照每一行切割读取
	datastrsplit := strings.Split(string(data), "\r\n")
	//大标签Tag的名称
	var LableTagName  string
	//大标签Filed 的名称
	var LableFieldName  string
	for _,line := range datastrsplit{
		//去除两边空格
		line =strings.TrimSpace(line)
		//判断这行数据是不是为空 或者是注释
		if len(line) == 0 || line[0] == '#' || line[0] == ';' {
			continue
		}
		//fmt.Printf("line:%q\n",line)
		//如果他是以 [ 开始 结尾] 说明他是一个大标签 server mysql
		//fmt.Printf("line HasPrefix:%v\n",strings.HasPrefix(line,"["))
		//fmt.Printf("line HasSuffix:%v\n",strings.HasSuffix(line,"]"))
		if strings.HasPrefix(line,"[") && strings.HasSuffix(line,"]") {
			LableTagName = line[1:strings.Index(line,"]")]
			//fmt.Printf("LableTagName:%v\n",LableTagName)
			//查找打标签 并且返回 大标签对应tag 结构体字段的名称 比如 server tag 对应结构体字段Server
			//最后需要通过结构体字段进行查找字段进行赋值
			LableFieldName = BigLablesFieldName(LableTagName, rt)
			//fmt.Printf("BigLablesFieldName LableFieldName:%v\n",LableFieldName)
			continue
		}

		//找出来key value 进行设置
		RefelectSetStruct(LableFieldName,line,v)
	}

	return
}
//查找打标签在反射结构体中的标签tag
func BigLablesFieldName(LableTagName string,rt reflect.Type) (LableFieldName string){
	//查找结构体中的字段
	//var LableFieldName string
	for i:=0;i<rt.Elem().NumField();i++{
		field := rt.Elem().Field(i)
		TagName := field.Tag.Get("ini")
		if LableTagName == TagName {
			LableFieldName=field.Name
			return
		}
	}
	return
}

//根据key value 进行设置到结构体
func RefelectSetStruct(LableFieldName string ,line string,v interface{}){
	//获取key 和 value 数据
	lines := strings.Split(line,"=")
	key := strings.TrimSpace(lines[0])
	value := strings.TrimSpace(lines[1])
	//fmt.Printf("key:%q value:%q\n",key,value)
	rf := reflect.TypeOf(v)
	filed, _ := rf.Elem().FieldByName(LableFieldName)
	rf = filed.Type

	//找出对应LableFieldName 对英的字段

	//进行比较 key 是不是 等于tagName
	var KeyFieldName string
	for i:=0;i< rf.NumField();i++{
		field := rf.Field(i)
		filedTagName := field.Tag.Get("ini")
		if key == filedTagName {
			KeyFieldName = field.Name
			continue
		}
	}
	//进行设置
	rv := reflect.ValueOf(v)
	rv = rv.Elem().FieldByName(LableFieldName)
	//fmt.Printf("Lablesvalues:%v\n",rv)
	filedvalues := rv.FieldByName(KeyFieldName)
	//fmt.Printf("filedvalues:%v\n",filedvalues)
	switch filedvalues.Kind() {
	case reflect.String:
		filedvalues.SetString(value)
	case reflect.Int:
		intvalue,_ := strconv.Atoi(value)
		filedvalues.SetInt(int64(intvalue))
	case reflect.Float64:
		valuefloat, _ := strconv.ParseFloat(value, 64)
		filedvalues.SetFloat(valuefloat)
	default:

	}
}


func Marshal(v interface{}) ([]byte, error) {
	//判断是不是结构体
	rt := reflect.TypeOf(v)
	//LableName := rt.Name()
	//fmt.Printf("[%v]\n",LableName)

	//fmt.Printf("rt:%#v\n",rt)
	rv := reflect.ValueOf(v)
	//fmt.Printf("rv%#v\n",rv)
	var results []byte
	var err error
	kind := rt.Kind()
	if kind != reflect.Struct{
		panic("必须是一个结构体")
	}
	for i:=0;i<rt.NumField();i++{
		fieldLable := rt.Field(i)
		//判断是不是普通的类似 如果是结构体需要重新进行解析
		//fmt.Printf("~~~~ fieldLable:%v\n",fieldLable)
		fieldLablevalue := rv.FieldByName(fieldLable.Name)
		kind := fieldLable.Type.Kind()
		if kind == reflect.Struct{
			//fmt.Printf("kind:%v\n",kind)
			Labname := fmt.Sprintf("[%v]\n",fieldLable.Name)
			//fmt.Printf("[%v]\n",fieldLable.Name)
			results=append(results,[]byte(Labname)...)
			for i:=0;i< fieldLable.Type.NumField();i++{
				field := fieldLable.Type.Field(i)
				fieldvalue:=fieldLablevalue.FieldByName(field.Name)
				fmt.Printf("key:%v = value:%v\n",field.Tag.Get("ini"),fieldvalue)
				results=append(results,[]byte(field.Tag.Get("ini")+" = ")...)
				switch fieldvalue.Kind() {
				case reflect.Int:
					value:=fieldvalue.Int()
					valurstr := fmt.Sprintf("%v\n",value)
					results=append(results,[]byte(valurstr)...)
				case reflect.Float64:
					value:=fieldvalue.Float()
					valurstr := fmt.Sprintf("%v\n",value)
					results=append(results,[]byte(valurstr)...)
				case reflect.String:
					results=append(results,[]byte(fieldvalue.String()+"\n")...)
				}

			}

		}
	}


	return results,err
}



func main(){
	data, err := ioutil.ReadFile("./config.ini")
	if err != nil {
		fmt.Println(err)
		return
	}
	var config Config
	fmt.Println("Unmarshal ini")
	err = Unmarshal(data,&config)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("config:%#v\n",config)

	fmt.Println()

	fmt.Println("Marshal ini")
	marshal, err := Marshal(config)
	fmt.Printf("%v\n",string(marshal))
}

标签:reflect,string,配置文件,fmt,LableFieldName,golang,ini,line,strings
来源: https://www.cnblogs.com/egrep/p/15272051.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有