Go实现一个简易的配置文件(ini)的解析器
Go实现⼀个简易的配置⽂件(ini)的解析器Go 实现⼀个简易的[ ini | properties ]配置⽂件的解析
因为什么需要 ini 配置⽂件?
⽅便管理项⽬的各种配置,⽐如 mysql、redis等配置
⽤到⽐较重要的知识点:reflect(反射)
本⽂不进⾏详细介绍,请⾃⾏进⾏查询相关资料
1、分析 ini ⽂件
内容如下 (project_dev.ini)
**关于 mysql 的配置块
[mysql]
## 数据库的连接地址
jdbc=jdbc:mysql://127.0.0.1:3306/test_db
/
/ 数据库的登录账户
username=oukele
# 数据库的登录密码
password=oukele..
**关于 redis 的配置块
[redis]
ip=127.0.0.1
port=1234
username=oukele
password=oukele..
当出现注释符号(**、##、//、#)或者 空⽩⾏时,不进⾏处理(这些数据对于程序来说不是必要的信息)2、读取 ini ⽂件的内容,并使⽤ map 接⼝储存药渍是什么性癖
// 跳过空⽩⾏、注释⾏
func ignoreComments(str string)bool{
if len(str)==0{
return true
}
if strings.HasPrefix(str,"**")|| strings.HasPrefix(str,"##")|| strings.HasPrefix(str,"//")|| strings.HasPrefix(str,"#"){ return true
}
return false
}
// ReadFileData /**读取配置⽂件的信息,并且分好配置块的信息
func ReadFileData(filePath string)(map[string]map[string]string,error){
file, err := ioutil.ReadFile(filePath)
if err !=nil{
return nil, err
}
// 初始化map
var allMap =make(map[string]map[string]string,5)
// 将字节转成字符串
str :=string(file)
strRow := strings.Split(str,"\n")
var currentKey =""
for_, row :=range strRow {
row = strings.TrimSpace(row)
if ignoreComments(row){
continue
}
// 获取到 [xxx] 的字符串
if strings.HasPrefix(row,"[")&& strings.HasSuffix(row,"]"){
// 去除所有的 [ 和 ]
row = strings.ReplaceAll(row,"[","")
row = strings.ReplaceAll(row,"]","")
// 去除字符误打的空格⽐如这样的 [ m y s q l ]
row = strings.ReplaceAll(row," ","")
_, ok := allMap[row]
// 此键已经存在则跳过
if ok {
continue
}
// 将当前的字符作为map的键,并初始化⾥边的 map
currentKey = row
瓷都是哪个城市allMap[row]=make(map[string]string,3)
continue
}
// 开头就不到键...就全部跳过,直到到键
if len(currentKey)==0{
continue
}
// 到第⼀个=然后分割开,⽐如 port=3306 --> key:port, value:3306
index := strings.Index(row,"=")
// 没到 = 也跳这⼀⾏的数据
if index ==-1{
continue
}
r :=[]rune(row)
key :=string(r[:index])
key = strings.ReplaceAll(key," ","")
val :=string(r[index+1:])
allMap[currentKey][key]= val
}
return allMap,nil
}
解析出来的结果如下
3、解析的数据,通过反射赋值到结构体中1、增加⼀个 MysqlConfig 的结构体
// MysqlConfig 结构体
type MysqlConfig struct{
Jdbc    string`ini:"jdbc"`
Username string`ini:"username"`
Password string`ini:"password"`
}
2、增加⼀个 RedisConfig 的结构体
// RedisConfig 结构体
type RedisConfig struct{
Ip      string`ini:"ip"`
Port    int`ini:"port"`
Username string`ini:"username"`
Password string`ini:"password"`
}
3、增加⼀个 Config 的结构体
type Config struct{
MysqlConfig `ini:"mysql"`
RedisConfig `ini:"redis"`
}
4、利⽤反射进⾏结构体的赋值函数代码
// LoadConfigFile 加载配置⽂件
func LoadConfigFile(filePath string, dataType interface{})error{ typeOf := reflect.TypeOf(dataType)
if typeOf.Kind()!= reflect.Ptr {
return errors.New("请传⼊⼀个指针的类型变量")
}
valueOf := reflect.ValueOf(dataType)
// 指针类型数据需要使⽤ Elem() ⽅法
if valueOf.Elem().Kind()!= reflect.Struct {
return errors.New("请传⼊⼀个指针的类型结构体变量")
}
allMap, err :=ReadFileData(filePath)
旅游管理就业前景if err !=nil{
return err
}
for i :=0; i < typeOf.Elem().NumField(); i++{
field := typeOf.Elem().Field(i)
fieldIniTag := field.Tag.Get("ini")
// 跳过没有 ini Tag 的字段
if fieldIniTag ==""{
continue
}
itemMap, ok := allMap[fieldIniTag]
// ⼤的key不存在时,⽐如没有 mysql 配置项时,直接跳过
if!ok {
continue
法国香水排行榜
}
// 取出这个字段的数据
structVal := valueOf.Elem().FieldByName(field.Name)
// 不是结构体的数据则跳过
if structVal.Kind()!= reflect.Struct {
continue
}
// 获取这个数据类型的结构信息
structType := structVal.Type()
for i :=0; i < structType.NumField(); i++{
structField := structType.Field(i)
structFieldIniTag := structField.Tag.Get("ini")
if structFieldIniTag ==""{
continue
}
s, ok := itemMap[structFieldIniTag]
// 没有此配置项时,跳过
if!ok {
continue
怎么装修房子}
fieldObj := structVal.FieldByName(structField.Name)
// 使⽤反射进⾏赋值
err :=setValue(&fieldObj, s)
if err !=nil{
fmt.Printf("[warn]字段[%s]⽆法进⾏赋值,error: %v\n", structField.Name, err)
}
}
}
return nil
}
// 使⽤反射进⾏赋值
func setValue(fieldObj *reflect.Value, value interface{})error{
value1 := value.(string)
switch fieldObj.Kind(){
case reflect.String:
fieldObj.SetString(value1)
case reflect.Int:
草莓种植atoi, err := strconv.Atoi(value1)
if err !=nil{
return err
}
fieldObj.SetInt(int64(atoi))
default:
return errors.New("缺少类型转换,请添加[ "+ fmt.Sprintf("%v", fieldObj.Kind())+" ]转换类型") }
return nil
}
5、使⽤
结果
[warn]字段[DefaultQuery]⽆法进⾏赋值,error:缺少类型转换,请添加[bool]转换类型
myini.MysqlConfig{Jdbc:"jdbc:mysql://127.0.0.1:3306/test_db", Username:"oukele", Password:"oukele..", DefaultQuery:false} myini.RedisConfig{Ip:"127.0.0.1", Port:1234, Username:"oukele", Password:"oukele.."}
DefaultQuery 字段是新添加的,可以忽略(我测试⽤的)
结尾
⼩菜鸟⼀枚,本⽂的⽬的只是为了加强对Go反射的理解,写得不好,请路过的⼤佬经喷~~

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。