最近迷恋go语言,但我是个编程菜鸟,这个读取参考了beego的config,只是半成品,不过能够正常运行。
- 接口的设计
type Parser interface {
Parse() error
}
type Config interface {
GetString(string)string
Parser
}
目前只支持最小操作,解析和获取。在读取之前,要让config实例化一个对象:
var config Config
func RegisterConfig(mode,path string){
switch mode{
case "ini":
config=ini.NewIniConfig(path)
case "json":
case "xml":
default:
panic("Dosn't Supported configure type.")
}
}
这样,只要Iniconfig实现了config接口,就能将实例化的对象赋值给config,这个对象是全局的,外部调用config.Regi...之后,调用封装好的操做即可获取实例,实现功能。
全局实现:util.go
package config import "mytools/config/ini" type Parser interface { Parse() error } type Config interface { GetString(string)string Parser } var config Config func RegisterConfig(mode,path string){ switch mode{ case "ini": config=ini.NewIniConfig(path) case "json": case "xml": default: panic("Dosn't Supported configure type.") } } func GetConfig()*Config{ return &config }
IniConfig实现
package ini
import (
"os"
"sync"
"bufio"
"io"
"bytes"
"strings"
"log"
)
var(
DEFAULT_SECTION string
COMMENT []byte
SEPARATOR []byte
//SECTION_START string
//SECTION_END string
)
//const(
// LEFT = iota
// RIGHT
//)
func init(){
DEFAULT_SECTION="default"
COMMENT=[]byte{'#'}
SEPARATOR=[]byte{'='}
}
//type EntryConfig struct {
// IsAlign bool //对齐
// AlignType int //对齐类型
//}
type IniEntry struct {
value interface {}
}
type IniConfig struct {
filename string
section map[string]*IniSection
sync.RWMutex
}
func NewIniConfig(path string) *IniConfig{
config:=&IniConfig{path,make(map[string]*IniSection),sync.RWMutex{}}
config.section[DEFAULT_SECTION]=NewIniSection()
return config
}
func (c *IniConfig)Parse() error{
file,err:=os.Open(c.filename)
if err!=nil {
return err
}
c.Lock()
defer c.Unlock()
defer file.Close()
buf:=bufio.NewReader(file)
section:=DEFAULT_SECTION
var bufRead int
for{
//读取一行缓存
line,_,err:=buf.ReadLine()
bufRead = bufRead + len(line)
if err==io.EOF{
//读到文件结尾,退出循环
break
}
if bytes.Equal(line,[]byte("")){
//空行直接跳过循环
continue
}
//删除行两端的空白字符
line=bytes.TrimSpace(line)
if bytes.HasPrefix(line,COMMENT){
//注释行暂时不做处理
continue
}
if bytes.HasPrefix(line,[]byte("["))&&bytes.HasSuffix(line,[]byte("]")){
//section处理
//现在line确定为"[sectioname]"
//不知道有没有合法性检查
section=string(line[1:len(line)-1])
section=strings.ToLower(section)
if _,ok:=c.section[section];!ok{
c.section[section]=NewIniSection()
}
}else{
//key=value处理
pair:= bytes.SplitN(line,SEPARATOR,2)
key:= pair[0]
val:=pair[1]
if _,ok:=c.section[section];!ok{
c.section[section]=NewIniSection()
}
log.Println(key,val)
c.section[section].addEntry(string(key),string(val))
}
}
return nil
}
func (c *IniConfig)RemoveSection(key string) error{
return nil
}
func (c *IniConfig)GetString(k string) string{
s:=strings.Split(k,":")
var sec string
var key string
if len(s)==1{
sec=DEFAULT_SECTION
key=s[0]
log.Println(sec,key)
}else{
sec=s[0]
key=s[1]
log.Println(sec,key)
}
if v,ok:=c.section[sec].getEntry(key).(string);ok{
return v
}
return ""
}
首先看结构,Ini文件最基本的组成由注释,模块,项三个部分,其中,注释行可能由特定的字符开头,比如“#”,“;”等,现在默认是"#",如果要支持自定义字符,添加接口和check操作就能实现。在模块加载时我们就已经定义好了默认操作。参见init函数。
在回过头看看section,iniconfig是一个深度为2的树结构,每个树的跟节点是sectionname,子节点是配置项key=value,默认有一个defaultsection。
在解析方面,逐行读取,然后根据ini文件特点,处理注释行,注释段(未实现),section,和项,之后把他们转换成数据结构保存在Iniconfig中,只要调用GetString即可拿到配置项,语法为"section:key"。
那么,先到这里吧。