最近迷恋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"。
那么,先到这里吧。