# Golang 利用反射实现读取配置文件

By [Robin](https://paragraph.com/@robin-8) · 2023-03-02

---

    package main
    
    import (
        "errors"
        "fmt"
        "io/ioutil"
        "reflect"
        "strings"
    )
    
    type MysqlConf struct {
        Address  string `ini:"address"`
        Port     string `ini:"port"`
        Username string `ini:"username"`
        Password string `ini:"password"`
    }
    
    type Redisconf struct {
        Host     string `ini:"host"`
        Port     string `ini:"port"`
        Password string `ini:"password"`
        Database string `ini:"database"`
    }
    
    type Conf struct {
        MysqlConf `ini:"mysql"`
        Redisconf `ini:"redis"`
    }
    
    func loadIni(fileName string, data interface{}) (err error) {
    
        t := reflect.TypeOf(data)
        v := reflect.ValueOf(data)
        //1 判断传进来指针 并且是结构体指针
        if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct {
            err = errors.New("input type is not Struct Ptr")
            return
        }
    
        //2. 读文件得到字节数据类型
        content, err := ioutil.ReadFile(fileName)
        if err != nil {
            err = errors.New("open file faild")
            return
        }
    
        //3. 一行一行读数据
        var sectionName string
        var structName string
    
        lines := strings.Split(string(content), "\n")
        for _, line := range lines {
            line = strings.TrimSpace(line)
    
            //3.1 空行跳过循环
            if len(line) == 0 {
                continue
            }
    
            //3.2 注释跳过循环
            if strings.HasPrefix(line, "#") {
                continue
            }
    
            //3.3 如果是 [ 开头就表示是section字段
            if strings.HasPrefix(line, "[") {
                sectionName = strings.TrimSpace(line[1 : len(line)-1])
                for i := 0; i < v.Elem().NumField(); i++ {
                    field := v.Elem().Type().Field(i)
                    if sectionName == field.Tag.Get("ini") {
                        structName = field.Name
                    }
                }
            } else {
                // 获取seciton下面的key and value
                key := strings.TrimSpace(strings.Split(line, "=")[0])
                value := strings.TrimSpace(strings.Split(line, "=")[1])
    
                // 获取嵌套里的struct
                structObj := v.Elem().FieldByName(structName)
    
                // 获取最终的字段
                var fieldName string
                for i := 0; i < structObj.NumField(); i++ {
                    field := structObj.Type().Field(i)
                    if key == field.Tag.Get("ini") {
                        fieldName = field.Name
                    }
                }
    
                //赋值操作
                structObj.FieldByName(fieldName).SetString(value)
            }
    
        }
    
        return nil
    }
    
    func main() {
        var cfg Conf
        err := loadIni("./conf.ini", &cfg)
        if err != nil {
            fmt.Println(err)
            return
        }
    
        fmt.Printf("Mysql address is:%s\n", cfg.MysqlConf.Address)
        fmt.Printf("Mysql port is:%s\n", cfg.MysqlConf.Port)
        fmt.Printf("Mysql username is:%s\n", cfg.MysqlConf.Username)
        fmt.Printf("Mysql password is:%s\n", cfg.MysqlConf.Password)
    
        fmt.Printf("Redis host is:%s\n", cfg.Redisconf.Host)
        fmt.Printf("Redis port is:%s\n", cfg.Redisconf.Port)
        fmt.Printf("Redis password is:%s\n", cfg.Redisconf.Password)
        fmt.Printf("Redis database is:%s\n", cfg.Redisconf.Database)
    }
    

**conf.ini**

    [mysql]
    address=192.168.100.100
    port=3306
    username=root
    password=BaVzJJJlNBS47uo9KduonCtMrdPhyYVG
    
    
    
    [redis]
    host= 127.0.0.1
    port= 6379
    password=123.com
    database=0

---

*Originally published on [Robin](https://paragraph.com/@robin-8/golang-6)*
