mirror of
https://github.com/xiaoqidun/goini.git
synced 2026-07-13 05:08:27 +08:00
291 lines
8.0 KiB
Go
291 lines
8.0 KiB
Go
package goini
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
defaultTag = "goini"
|
|
defaultSeparator = " = "
|
|
defaultRootSection = "BuiltCommon"
|
|
)
|
|
|
|
var (
|
|
errFilenameRequired = errors.New("filename required")
|
|
errStructPointerRequired = errors.New("struct pointer required")
|
|
)
|
|
|
|
// GoINI 表示INI配置解析器
|
|
type GoINI struct {
|
|
data []byte
|
|
filename string
|
|
fileLines []iniLine
|
|
structTag string
|
|
rootSection string
|
|
sectionKeys map[string][]string
|
|
sectionOrder []string
|
|
sectionValues map[string]map[string]string
|
|
sectionLineIndexes map[string]int
|
|
sectionKeyLineIndexes map[string]map[string]int
|
|
}
|
|
|
|
// NewGoINI 创建GoINI对象
|
|
// 返回: *GoINI GoINI对象
|
|
func NewGoINI() *GoINI {
|
|
return &GoINI{structTag: defaultTag, rootSection: defaultRootSection}
|
|
}
|
|
|
|
// SetData 从字节内容读取配置并解析
|
|
// 入参: fileData 配置文件内容
|
|
func (ini *GoINI) SetData(fileData []byte) {
|
|
ini.filename = ""
|
|
ini.data = append(ini.data[:0], fileData...)
|
|
ini.parse()
|
|
}
|
|
|
|
// LoadFile 从文件读取配置并解析
|
|
// 入参: filename 配置文件路径
|
|
// 返回: error 错误信息
|
|
func (ini *GoINI) LoadFile(filename string) error {
|
|
b, err := os.ReadFile(filename)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ini.filename = filename
|
|
ini.data = append(ini.data[:0], b...)
|
|
ini.parse()
|
|
return nil
|
|
}
|
|
|
|
// Save 将配置写回LoadFile读取的文件
|
|
// 返回: error 错误信息
|
|
func (ini *GoINI) Save() error {
|
|
if ini.filename == "" {
|
|
return errFilenameRequired
|
|
}
|
|
return ini.SaveFile(ini.filename)
|
|
}
|
|
|
|
// SaveFile 将配置写入指定文件
|
|
// 入参: filename 配置文件路径
|
|
// 返回: error 错误信息
|
|
func (ini *GoINI) SaveFile(filename string) error {
|
|
if filename == "" {
|
|
return errFilenameRequired
|
|
}
|
|
if err := os.WriteFile(filename, []byte(ini.String()), 0o666); err != nil {
|
|
return err
|
|
}
|
|
ini.filename = filename
|
|
return nil
|
|
}
|
|
|
|
// String 获取GoINI对象的字符串形式
|
|
// 返回: string 配置文件内容
|
|
func (ini *GoINI) String() string {
|
|
renderedLines := make([]string, len(ini.fileLines))
|
|
for i, line := range ini.fileLines {
|
|
renderedLines[i] = renderLine(line)
|
|
}
|
|
return strings.Join(renderedLines, "\n")
|
|
}
|
|
|
|
// SetString 设置单个配置项的字符串值
|
|
// 入参: name 分区名称, key 配置项名称, value 配置项值
|
|
func (ini *GoINI) SetString(name string, key string, value string) {
|
|
ini.ensureParsed()
|
|
name = ini.normalizeSection(name)
|
|
key = strings.TrimSpace(key)
|
|
if key == "" {
|
|
return
|
|
}
|
|
if index, ok := ini.findSectionKeyLineIndex(name, key); ok {
|
|
ini.fileLines[index].keyValue = value
|
|
ini.fileLines[index].modified = true
|
|
ini.rebuildIndexes()
|
|
return
|
|
}
|
|
ini.ensureSectionLine(name)
|
|
ini.insertLine(ini.findSectionInsertIndex(name), iniLine{kind: lineKeyValue, sectionName: name, keyName: key, keyValue: value, separator: defaultSeparator})
|
|
}
|
|
|
|
// SetBool 设置单个配置项的布尔值
|
|
// 入参: name 分区名称, key 配置项名称, value 配置项值
|
|
func (ini *GoINI) SetBool(name string, key string, value bool) {
|
|
ini.SetString(name, key, strconv.FormatBool(value))
|
|
}
|
|
|
|
// SetInt64 设置单个配置项的整数值
|
|
// 入参: name 分区名称, key 配置项名称, value 配置项值
|
|
func (ini *GoINI) SetInt64(name string, key string, value int64) {
|
|
ini.SetString(name, key, strconv.FormatInt(value, 10))
|
|
}
|
|
|
|
// SetFloat64 设置单个配置项的浮点数值
|
|
// 入参: name 分区名称, key 配置项名称, value 配置项值
|
|
func (ini *GoINI) SetFloat64(name string, key string, value float64) {
|
|
ini.SetString(name, key, strconv.FormatFloat(value, 'f', -1, 64))
|
|
}
|
|
|
|
// SetComment 设置配置项注释,空注释会删除已有注释
|
|
// 入参: name 分区名称, key 配置项名称, comment 注释内容
|
|
// 返回: bool 是否设置成功
|
|
func (ini *GoINI) SetComment(name string, key string, comment string) bool {
|
|
if key == "" {
|
|
return ini.SetSectionComment(name, comment)
|
|
}
|
|
ini.ensureParsed()
|
|
name = ini.normalizeSection(name)
|
|
key = strings.TrimSpace(key)
|
|
index, ok := ini.findSectionKeyLineIndex(name, key)
|
|
if !ok {
|
|
return false
|
|
}
|
|
ini.replaceCommentBefore(index, comment)
|
|
return true
|
|
}
|
|
|
|
// SetSectionComment 设置分区注释,空注释会删除已有注释
|
|
// 入参: name 分区名称, comment 注释内容
|
|
// 返回: bool 是否设置成功
|
|
func (ini *GoINI) SetSectionComment(name string, comment string) bool {
|
|
ini.ensureParsed()
|
|
name = ini.normalizeSection(name)
|
|
if name == ini.rootSection {
|
|
ini.replaceCommentBefore(ini.firstRootLineIndex(), comment)
|
|
return true
|
|
}
|
|
ini.ensureSectionLine(name)
|
|
index, ok := ini.findSectionLineIndex(name)
|
|
if !ok {
|
|
return false
|
|
}
|
|
ini.replaceCommentBefore(index, comment)
|
|
return true
|
|
}
|
|
|
|
// GetNames 获取配置文件分区列表
|
|
// 入参: match 分区名称正则表达式
|
|
// 返回: []string 分区名称列表
|
|
func (ini *GoINI) GetNames(match string) []string {
|
|
return matchStrings(ini.sectionOrder, match)
|
|
}
|
|
|
|
// GetNameKeys 获取分区下配置项列表
|
|
// 入参: name 分区名称, match 配置项名称正则表达式
|
|
// 返回: []string 配置项名称列表
|
|
func (ini *GoINI) GetNameKeys(name string, match string) []string {
|
|
name = ini.normalizeSection(name)
|
|
return matchStrings(ini.sectionKeys[name], match)
|
|
}
|
|
|
|
// GetString 获取单个配置项的字符串值
|
|
// 入参: name 分区名称, key 配置项名称, value 默认值
|
|
// 返回: string 配置项值
|
|
func (ini *GoINI) GetString(name string, key string, value string) string {
|
|
name = ini.normalizeSection(name)
|
|
if v, ok := ini.sectionValues[name]; ok {
|
|
if vv, ok := v[key]; ok {
|
|
return vv
|
|
}
|
|
}
|
|
return value
|
|
}
|
|
|
|
// GetBool 获取单个配置项的布尔值
|
|
// 入参: name 分区名称, key 配置项名称, value 默认值
|
|
// 返回: bool 配置项值
|
|
func (ini *GoINI) GetBool(name string, key string, value bool) bool {
|
|
boolStr := ini.GetString(name, key, "")
|
|
switch strings.ToLower(boolStr) {
|
|
case "y", "yes", "on":
|
|
return true
|
|
case "n", "no", "off":
|
|
return false
|
|
}
|
|
if b, e := strconv.ParseBool(boolStr); e == nil {
|
|
return b
|
|
}
|
|
return value
|
|
}
|
|
|
|
// GetInt64 获取单个配置项的整数值
|
|
// 入参: name 分区名称, key 配置项名称, value 默认值
|
|
// 返回: int64 配置项值
|
|
func (ini *GoINI) GetInt64(name string, key string, value int64) int64 {
|
|
int64Str := ini.GetString(name, key, "")
|
|
if i, e := strconv.ParseInt(int64Str, 10, 64); e == nil {
|
|
return i
|
|
}
|
|
return value
|
|
}
|
|
|
|
// GetFloat64 获取单个配置项的浮点数值
|
|
// 入参: name 分区名称, key 配置项名称, value 默认值
|
|
// 返回: float64 配置项值
|
|
func (ini *GoINI) GetFloat64(name string, key string, value float64) float64 {
|
|
float64Str := ini.GetString(name, key, "")
|
|
if f, e := strconv.ParseFloat(float64Str, 64); e == nil {
|
|
return f
|
|
}
|
|
return value
|
|
}
|
|
|
|
// GetComment 获取配置项注释
|
|
// 入参: name 分区名称, key 配置项名称
|
|
// 返回: string 注释内容
|
|
func (ini *GoINI) GetComment(name string, key string) string {
|
|
if key == "" {
|
|
return ini.GetSectionComment(name)
|
|
}
|
|
ini.ensureParsed()
|
|
name = ini.normalizeSection(name)
|
|
index, ok := ini.findSectionKeyLineIndex(name, strings.TrimSpace(key))
|
|
if !ok {
|
|
return ""
|
|
}
|
|
return ini.commentBefore(index)
|
|
}
|
|
|
|
// GetSectionComment 获取分区注释
|
|
// 入参: name 分区名称
|
|
// 返回: string 注释内容
|
|
func (ini *GoINI) GetSectionComment(name string) string {
|
|
ini.ensureParsed()
|
|
name = ini.normalizeSection(name)
|
|
if name == ini.rootSection {
|
|
return ini.commentBefore(ini.firstRootLineIndex())
|
|
}
|
|
index, ok := ini.findSectionLineIndex(name)
|
|
if !ok {
|
|
return ""
|
|
}
|
|
return ini.commentBefore(index)
|
|
}
|
|
|
|
// SetTag 设置结构体的tag键名称
|
|
// 入参: tag tag键名称
|
|
func (ini *GoINI) SetTag(tag string) {
|
|
ini.structTag = tag
|
|
}
|
|
|
|
// MapToStruct 将配置映射到一个结构体
|
|
// 入参: ptr 结构体指针
|
|
// 返回: error 错误信息
|
|
func (ini *GoINI) MapToStruct(ptr interface{}) error {
|
|
v := reflect.ValueOf(ptr)
|
|
if !v.IsValid() || v.Kind() != reflect.Ptr || v.IsNil() {
|
|
return errStructPointerRequired
|
|
}
|
|
v = v.Elem()
|
|
if v.Kind() != reflect.Struct {
|
|
return errStructPointerRequired
|
|
}
|
|
ini.mapStruct(v)
|
|
return nil
|
|
}
|