iGO实现之路 —— Config

本文为转载,原文:iGO实现之路 —— Config

Golang

介绍

相信大多数的程序员在使用各种框架开发的时候,都会有一个配置文件让我们做一些配置,比如说数据库的配置,缓存的配置,调试的配置等等,这些配置只要我们填写之后就会生效。

今天,我就用go语言实现是个读取配置文件的小模块。可能并不是非常的完成,或者还会存在一些不安全的因素。这里我将我的实现写出来,望发现问题的同学们提出来,我们大家共同进步。

源码地址

igo-github源码地址

实现

config 模块的文件列表如下图所示:


文件列表
  • conf 目录为功能模块

  • example 目录为测试代码

功能实现

config.go

由于我们的配置文件类型可能是多种多样的,比如ini,json等。所以,我首先得做一个Config的接口:

type Config interface{
    GetString(string) string
    GetInt(string)(int, error)
    GetInt64(string)(int64, error)
    GetFloat(string)(float64, error)
    GetBool(string)(bool, error)
}

从代码中看,我们的接口比较简单,就是一些从配置文件中读取各种类型的值,这里先暂时支持string,int,int64,float,bool类型的数据读取,后续如有需要再更新。

有了接口,就便于我们同意操作了。下面我们再做一个实例化的函数,这个就有点类型简单工厂模式了。根据参数创建不同类型的实例:

func NewConfig(adapter, filename string) (Config, error){
    path, err := GetCurrentPath(filename)
    if err != nil{
        return nil, err
    }
    switch adapter{
    case "ini":
        return GetIniConfig(path)
    default:
        return nil, errors.New("系统暂未处理该类型的配置文件")
    }
}

该函数有2个参数,adapter为我们适配的配置文件类型,如ini, json等。filename为我们的配置文件的相对路径。
代码通过不同的adapter返回不同的实例。该函数中调用了个GetCurrentPath函数。

下面,我们看下GetCurrentPath函数的实现:

func GetCurrentPath(filename string) (path string, err error ){
    path, err = filepath.Abs(filename)
    if err != nil {
        return
    }
    path = strings.Replace(path, "\\", "/", -1)
    path = strings.Replace(path, "\\\\", "/", -1)
    return
}

该函数的作用是将配置文件的相对路径转换为绝对路径。
至此,我们的公用的代码已经完成了。接下来就是各种不同的配置文件的实现了,也就是各种对于Config接口实现的方案。

完整的config.go代码如下:

package conf

import (
    "strings"
    "errors"

    "path/filepath"
)

type Config interface{
    GetString(string) string
    GetInt(string)(int, error)
    GetInt64(string)(int64, error)
    GetFloat(string)(float64, error)
    GetBool(string)(bool, error)
}

func NewConfig(adapter, filename string) (Config, error){
    path, err := GetCurrentPath(filename)
    if err != nil{
        return nil, err
    }
    switch adapter{
    case "ini":
        return GetIniConfig(path)
    default:
        return nil, errors.New("系统暂未处理该类型的配置文件")
    }
}

func GetCurrentPath(filename string) (path string, err error ){
    path, err = filepath.Abs(filename)
    if err != nil {
        return
    }
    path = strings.Replace(path, "\\", "/", -1)
    path = strings.Replace(path, "\\\\", "/", -1)
    return
}

ini

ini_config.go

INI文件格式是某些平台或软件上的配置文件的非正式标准,以节(section)和键(key)构成,常用于微软Windows操作系统中。这种配置文件的文件扩展名多为INI,故名。

INI是英文“初始化”(initialization)的缩写。正如该术语所表示的,INI文件被用来对操作系统或特定程序初始化或进行参数设置。

既然知道了ini文件,那么我们就看看怎么去读取其配置吧。
先看下对于IniConfig的结构体定义:

type IniConfig struct{
    ConfigMap  map[string]string
    strcet string
}

从config.go代码文件中的NewConfig函数中,我们看到了这样一个函数GetIniConfig,而该函数就是对于ini文件配置的初始化:

func GetIniConfig(filename string)(*IniConfig, error){
    middle := "."
    config :=  new(IniConfig)
    config.ConfigMap = make(map[string]string)
    //打开文件
    file, err := os.Open(filename)
    if err != nil{
        return nil, err
    }
    defer file.Close()
    read := bufio.NewReader(file)
    for{
        b, _, err := read.ReadLine()
        if err != nil {
            if err == io.EOF{
                break
            }
            return nil, err
        }
        str := strings.TrimSpace(string(b))
        //配置文件中的注释
        if strings.Index(str, "#") == 0{
            continue
        }
        //配置文件中的前缀处理
        n1 := strings.Index(str, "[")
        n2 := strings.LastIndex(str, "]")
        if n1 > -1 && n2 > -1 && n2 > n1 + 1{
            config.strcet = strings.TrimSpace(str[n1 + 1 : n2])
            continue
        }
        if len(config.strcet) < 1{
            continue
        }
        //
        eqIndex := strings.Index(str, "=")
        if eqIndex < 0{
            continue
        }
        eqLeft := strings.TrimSpace(str[0:eqIndex])
        if len(eqLeft) < 1{
            continue
        }
        eqRight := strings.TrimSpace(str[eqIndex+1:])
        pos := strings.Index(eqRight,"\t#")
        val := eqRight
        if pos > -1{
            val = strings.TrimSpace(eqRight[0:pos])
        }

        pos = strings.Index(eqRight, " #")
        if pos > -1{
            val = strings.TrimSpace(eqRight[0:pos])
        }

        pos = strings.Index(eqRight, "\t//")
        if pos > -1{
            val = strings.TrimSpace(eqRight[0:pos])
        }

        pos = strings.Index(eqRight, " //")
        if pos > -1{
            val = strings.TrimSpace(eqRight[0:pos])
        }
        if len(val) < 1{
            continue
        }
        key := config.strcet + middle + eqLeft
        config.ConfigMap[key] = strings.TrimSpace(val)
    }
    return config, nil
}

然后再有一个按key来获取配置的val的字符串的函数:

func (self *IniConfig) Get(key string)string{
    v, ok := self.ConfigMap[key]
    if ok{
        return v
    }
    return ""
}

剩下来就是对于Config接口的实现了:

func (self *IniConfig) GetString(key string)string{
    return self.Get(key)
}

func (self *IniConfig) GetInt(key string)(int, error){
    return strconv.Atoi(self.Get(key))
}

func (self *IniConfig) GetInt64(key string)(int64, error){
    return strconv.ParseInt(self.Get(key), 10, 64)
}

func (self *IniConfig) GetFloat(key string)(float64, error){
    return strconv.ParseFloat(self.Get(key), 64)
}

func (self *IniConfig) GetBool(key string)(bool, error){
    return strconv.ParseBool(self.Get(key))
}

ini_config.go的实现就这些。当然了,package和import也是肯定有的啦:

package conf

import (
    "strings"
    "strconv"

    "io"
    "bufio"
    "os"
)

上面的这些代码整合到一起就是ini_config.go的完整代码了。

测试

上面那些,也就简单的实现了配置文件的读取功能了。但是能不能用呢?我们简单的做个测试吧。
/example/config/app.config中写一些简单的配置信息:

[default]
string = string
int = 10
int64 = 100000
float = 123.456
bool = true

然后在/example/test_config.go读取试一下:

package main

import(
    "fmt"
    "igo/conf"
)

func main(){
    config,err := conf.NewConfig("ini", "config/app.config")
    if err != nil{
        fmt.Println(err.Error())
        return
    }
    strVal := config.GetString("default.string")
    fmt.Println("string value:", strVal)

    intVal, err := config.GetInt("default.int")
    if err != nil{
        fmt.Println("get int value error: ", err.Error())
    }
    fmt.Println("int value: ", intVal)

    int64Val, err := config.GetInt64("default.int64")
    if err != nil{
        fmt.Println("get int64 value error: ", err.Error())
    }
    fmt.Println("int64 value: ", int64Val)
    
    floatVal, err := config.GetFloat("default.float")
    if err != nil{
        fmt.Println("get float value error: ", err.Error())
    }
    fmt.Println("float value: ", floatVal)

    boolVal, err := config.GetBool("default.bool")
    if err != nil{
        fmt.Println("get bool value error: ", err.Error())
    }
    fmt.Println("bool value: ", boolVal)
}

结果如下:


config测试结果

转载请注明出处:
iGO实现之路 —— Config

iGO我的go语言库

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,569评论 25 707
  • 关于身体,今天有了一个新的发现,刷朋友圈,看到高学斌医生的朋友圈发了一个关于护腰带的动态,然后就留言说自己也带过很...
    112233D阅读 132评论 0 0
  • 知我者与我相惜, 不知我者自相离; 人生尽九全九美, 我以笑对恶人指。
    他说这不是诗阅读 98评论 0 0
  • 读的什么书:《今天之礼教杀人》 阅读有效时间:半小时 阅读中遇到了什么困难:看书时间有点晚,精神状态不太好 阅读有...
    虔一阅读 341评论 0 0