Go利用反射实现一个ini文件的解析器程序

package main

import (
	"bufio"  // 逐行读取配置文件
	"fmt"
	"log"
	"os"
	"reflect"
	"strconv"
	"strings"
)

type Config struct {	// 定义配置结构体
	Section1 Section1 `ini:"section1"`	// 嵌套结构体1
	Section2 Section2 `ini:"section2"`	// 嵌套结构体2
}

type Section1 struct {
	Key1 string `ini:"key1"`
	Key2 int    `ini:"key2"`
}

type Section2 struct {
	Key3 float64 `ini:"key3"`
	Key4 bool    `ini:"key4"`
}

// fieldName 函数返回一个匹配函数,用于在结构体中查找字段名与给定字段名相同的字段
func fieldName(fieldName string) func(string) bool {
	return func(tag string) bool {
		return strings.EqualFold(tag, fieldName)	// 调用strings.EqualFold 函数进行不区分大小写匹配
	}
}

func main() {
	file, err := os.Open("config.ini")
	if err != nil {
		log.Fatalf("Failed to open file: %v", err)
	}
	defer file.Close()

	cfg := Config{}
	scanner := bufio.NewScanner(file)
	currentSection := ""
	v := reflect.ValueOf(&cfg).Elem()

	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())

		if line == "" || strings.HasPrefix(line, "#") {
			continue
		}

		if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
			currentSection = strings.Trim(line, "[]")
			sectionField := v.FieldByNameFunc(fieldName(currentSection))
			if !sectionField.IsValid() {
				log.Printf("Invalid section: %s", currentSection)
			}
		} else {
			parts := strings.SplitN(line, "=", 2)
			if len(parts) != 2 {
				log.Printf("Invalid key-value pair: %s", line)
				continue
			}

			key := strings.TrimSpace(parts[0])
			value := strings.TrimSpace(parts[1])

			if currentSection == "" {
				log.Printf("Key-value pair found outside of any section: %s", line)
				continue
			}

			sectionField := v.FieldByNameFunc(fieldName(currentSection))
			if !sectionField.IsValid() {
				log.Printf("Invalid section: %s", currentSection)
				continue
			}

			field := sectionField.FieldByNameFunc(fieldName(key))
			if !field.IsValid() {
				log.Printf("Invalid key: %s", key)
				continue
			}

			switch field.Kind() {
			case reflect.String:
				field.SetString(value)
			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				intValue, err := strconv.ParseInt(value, 10, 64)
				if err != nil {
					log.Printf("Failed to parse int value for key %s: %v", key, err)
					continue
				}
				field.SetInt(intValue)
			case reflect.Float32, reflect.Float64:
				floatValue, err := strconv.ParseFloat(value, 64)
				if err != nil {
					log.Printf("Failed to parse float value for key %s: %v", key, err)
					continue
				}
				field.SetFloat(floatValue)
			case reflect.Bool:
				boolValue, err := strconv.ParseBool(value)
				if err != nil {
					log.Printf("Failed to parse bool value for key %s: %v", key, err)
					continue
				}
				field.SetBool(boolValue)
			default:
				log.Printf("Unsupported field type for key %s", key)
			}
		}
	}

	if err := scanner.Err(); err != nil {
		log.Fatalf("Error while scanning file: %v", err)
	}

	fmt.Printf("%+v\n", cfg)
}
[Section1]
key1 = value1
key2 = 100

[Section2]
key3 = 3.14
key4 = true

在这里插入图片描述

你可能感兴趣的:(#,Golang,golang,开发语言,后端)