配置文件管理

This commit is contained in:
John
2018-01-19 15:26:28 +08:00
parent a6ace7ff53
commit 5dab00fddb
6 changed files with 118 additions and 456 deletions

View File

@ -13,6 +13,9 @@ import (
"io/ioutil"
"encoding/json"
"gitee.com/johng/gf/g/util/gconv"
"gitee.com/johng/gf/g/os/gfile"
"errors"
"gitee.com/johng/gf/g/encoding/gxml"
)
// json解析结果存放数组
@ -39,7 +42,7 @@ func Decode (b []byte) (interface{}, error) {
}
}
// 解析json字符串为go变量注意第二个参数为指针
// 解析json字符串为go变量注意第二个参数为指针(任意结构的变量)
func DecodeTo (b []byte, v interface{}) error {
return json.Unmarshal(b, v)
}
@ -53,13 +56,22 @@ func DecodeToJson (b []byte) (*Json, error) {
}
}
// 加载json文件内容并转换为json对象
// 支持多种配置文件类型转换为json格式内容并解析为gjson.Json对象
// 支持的配置文件格式xml, json, yml
func Load (path string) (*Json, error) {
var result interface{}
data, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
var result interface{}
switch gfile.Ext(path) {
case ".xml":
data, err = gxml.ToJson(data)
if err != nil {
return nil, err
}
case ".yml":
}
if err := json.Unmarshal(data, &result); err != nil {
return nil, err
}

View File

@ -1,443 +0,0 @@
// Copyright 2017 gf Author(https://gitee.com/johng/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://gitee.com/johng/gf.
package internal
import (
"fmt"
"errors"
"strings"
"strconv"
)
// 这是一个自己开发的使用go进行json语法解析的解析器效率没有官方的json解析高仅作学习参考
const (
gJSON_CHAR_BRACE_LEFT = rune('{')
gJSON_CHAR_BRACE_RIGHT = rune('}')
gJSON_CHAR_BRACKET_LEFT = rune('[')
gJSON_CHAR_BRACKET_RIGHT = rune(']')
gJSON_CHAR_QUOTATION = rune('\\')
gJSON_CHAR_COMMA = rune(',')
gJSON_CHAR_COLON = rune(':')
gJSON_CHAR_DOUBLE_QUOTE_MARK = rune('"')
)
const (
gJSON_TOKEN_BRACE_LEFT = rune('{')
gJSON_TOKEN_BRACE_RIGHT = rune('}')
gJSON_TOKEN_BRACKET_LEFT = rune('[')
gJSON_TOKEN_BRACKET_RIGHT = rune(']')
gJSON_TOKEN_COMMA = rune(',')
gJSON_TOKEN_COLON = rune(':')
gJSON_TOKEN_STRING = rune('"')
gJSON_TOKEN_NUMBER = rune('0')
)
// json关联数组(哈希表)
type JsonMap map[string]interface{}
// json索引数组(普通数组从0开始索引)
type JsonArray []interface{}
// JSON数据对象
type gJsonNode struct {
m JsonMap
a JsonArray
}
// JSON语义token
type gJsonToken struct {
token []rune // token字符串
tokenType rune // token类型
tokenindex int // token在原始字符串中的索引位置
}
// JSON解析结构对象
type gJsonParser struct {
content []rune // 需要解析json字符串(通过string转换为[]rune)
tokens []gJsonToken // 存放解析content后的json token数组
root *gJsonNode // json根节点
pointer *gJsonNode // 指向当前正在解析的json节点
}
// 解析json字符串
func Decode(j *string) (*gJsonParser, error) {
p := &gJsonParser{content:[]rune(*j)}
err := p.parse()
if err == nil {
return p, err
} else {
return nil, err
}
}
// 判断所给字符串是否为数字
func isNumeric(s string) bool {
for i :=0; i < len(s); i++ {
if s[i] < byte('0') || s[i] > byte('9') {
return false
}
}
return true
}
// 获得一个键值对关联数组/哈希表,方便操作,不需要自己做类型转换
// 注意如果获取的值不存在或者类型与json类型不匹配那么将会返回nil
func (p *gJsonParser) GetMap(pattern string) JsonMap {
result := p.Get(pattern)
if result != nil {
if r, ok := result.(JsonMap); ok {
return r
}
}
return nil
}
// 获得一个数组[]interface{},方便操作,不需要自己做类型转换
// 注意如果获取的值不存在或者类型与json类型不匹配那么将会返回nil
func (p *gJsonParser) GetArray(pattern string) JsonArray {
result := p.Get(pattern)
if result != nil {
if r, ok := result.(JsonArray); ok {
return r
}
}
return nil
}
// 根据约定字符串方式访问json解析数据参数形如 "items.name.first", "list.0"
// 返回的结果类型的interface{},因此需要自己做类型转换
// 如果找不到对应节点的数据返回nil
func (p *gJsonParser) Get(pattern string) interface{} {
var result interface{}
pointer := p.root
array := strings.Split(pattern, ".")
length := len(array)
for i:= 0; i < length; i++ {
// 优先判断数组
if isNumeric(array[i]) {
n, err := strconv.Atoi(array[i])
if err == nil && len(pointer.a) > n {
if i == length - 1 {
result = pointer.a[n]
break;
} else {
if p, ok := pointer.a[n].(*gJsonNode); ok {
pointer = p
continue
}
}
}
}
// 其次判断哈希表如果一个键在数组及map中均不存在直接返回nil
if v, ok := pointer.m[array[i]]; ok {
if i == length - 1 {
result = v
} else {
if p, ok := v.(*gJsonNode); ok {
pointer = p
continue
}
}
} else {
return nil
}
}
// 处理结果如果是gJsonNode类型那么需要做转换
if r, ok := result.(*gJsonNode); ok {
if len(r.m) < 1 {
return r.a
} else {
return r.m
}
}
return result
}
// 遍历json字符串数组并且判断转义
func (p *gJsonParser) getNextChar(c rune, f int) int {
for i := f + 1; i < len(p.content); i++ {
if p.content[i] == c {
if i > 0 && p.content[i - 1] != gJSON_CHAR_QUOTATION {
return i
}
} else {
switch p.content[i] {
case gJSON_CHAR_DOUBLE_QUOTE_MARK:
r := p.getNextChar(gJSON_CHAR_DOUBLE_QUOTE_MARK, i)
if r > 0 {
i = r
}
}
}
}
return 0
}
// 判断字符是否为数字
func (p *gJsonParser) isCharNumber(c rune) bool {
if c >= rune('0') && c <= rune('9') {
return true
}
return false
}
// 按照json语法对保存的字符串进行解析
func (p *gJsonParser) parse() error {
// 首先将字符串解析成token进行保存
for i := 0; i < len(p.content); i++ {
if p.isCharNumber(p.content[i]) {
j := i + 1
for ; j < len(p.content); j++ {
if !p.isCharNumber(p.content[j]) {
break;
}
}
p.tokens = append(p.tokens, gJsonToken {
token: p.content[i:j],
tokenType: gJSON_TOKEN_NUMBER,
tokenindex: i,
})
i = j - 1
} else {
switch p.content[i] {
case gJSON_CHAR_DOUBLE_QUOTE_MARK:
r := p.getNextChar(gJSON_CHAR_DOUBLE_QUOTE_MARK, i)
if r > 0 {
// 注意这里需要去掉字符串两边的双引号
p.tokens = append(p.tokens, gJsonToken {
token: p.content[i+1:r],
tokenType: gJSON_TOKEN_STRING,
tokenindex: i,
})
i = r
}
case gJSON_CHAR_COLON:
p.tokens = append(p.tokens, gJsonToken{token: p.content[i:i+1], tokenType: gJSON_TOKEN_COLON, tokenindex: i})
case gJSON_CHAR_COMMA:
p.tokens = append(p.tokens, gJsonToken{token: p.content[i:i+1], tokenType: gJSON_TOKEN_COMMA, tokenindex: i})
case gJSON_CHAR_BRACE_LEFT:
p.tokens = append(p.tokens, gJsonToken{token: p.content[i:i+1], tokenType: gJSON_TOKEN_BRACE_LEFT, tokenindex: i})
case gJSON_CHAR_BRACE_RIGHT:
p.tokens = append(p.tokens, gJsonToken{token: p.content[i:i+1], tokenType: gJSON_TOKEN_BRACE_RIGHT, tokenindex: i})
case gJSON_CHAR_BRACKET_LEFT:
p.tokens = append(p.tokens, gJsonToken{token: p.content[i:i+1], tokenType: gJSON_TOKEN_BRACKET_LEFT, tokenindex: i})
case gJSON_CHAR_BRACKET_RIGHT:
p.tokens = append(p.tokens, gJsonToken{token: p.content[i:i+1], tokenType: gJSON_TOKEN_BRACKET_RIGHT, tokenindex: i})
default:
c := string(p.content[i])
if c != " " && c != "\r" && c != "\n" && c != "\t" {
return errors.New(fmt.Sprintf("json parse error: invalid char '%s' at index %d", c, i))
}
}
}
}
// 最后对解析后的token转换为go变量
return p.parseTokenNodeToVar(0, len(p.tokens) - 1)
}
// 获取json范围字符包含范围最右侧的索引位置
func (p *gJsonParser)getTokenBorderRightIndex(token rune, from int) int {
switch token {
case gJSON_TOKEN_BRACE_LEFT:
leftCount := 0
for i := from + 1; i < len(p.tokens); i++ {
if p.tokens[i].tokenType == gJSON_TOKEN_BRACE_LEFT {
leftCount ++
} else if p.tokens[i].tokenType == gJSON_TOKEN_BRACE_RIGHT {
if leftCount < 1 {
return i
} else {
leftCount--
}
}
}
case gJSON_CHAR_BRACKET_LEFT:
leftCount := 0
for i := from + 1; i < len(p.tokens); i++ {
if p.tokens[i].tokenType == gJSON_CHAR_BRACKET_LEFT {
leftCount ++
} else if p.tokens[i].tokenType == gJSON_CHAR_BRACKET_RIGHT {
if leftCount < 1 {
return i
} else {
leftCount--
}
}
}
}
return 0
}
// 将解析过后的json token转换为go变量
func (p *gJsonParser) parseTokenNodeToVar(left int, right int) error {
//fmt.Println("================================")
//for i := left; i <= right; i++ {
// fmt.Println(string(p.tokens[i].token))
//}
for i := left; i <= right; i++ {
//fmt.Println(string(p.tokens[i].token))
switch p.tokens[i].tokenType {
case gJSON_TOKEN_BRACE_LEFT:
fallthrough
case gJSON_TOKEN_BRACKET_LEFT:
node := newJsonNode()
// 判断根节点
if p.root == nil {
p.root = node
p.pointer = node
}
// 判断层级关系
borderRight := p.getTokenBorderRightIndex(p.tokens[i].tokenType, i)
if borderRight < 1 {
return errors.New(fmt.Sprintf("json parse error: unclosed tag '%s' at index %d", string(p.tokens[i].token), p.tokens[i].tokenindex))
}
if i > 1 && (
p.tokens[i-1].tokenType == gJSON_TOKEN_COLON &&
p.tokens[i-2].tokenType == gJSON_TOKEN_STRING) {
// json赋值操作
oldptr := p.pointer
k := string(p.tokens[i-2].token)
p.pointer.m[k] = node
p.pointer = node
err := p.parseTokenNodeToVar(i + 1, borderRight - 1)
if err != nil {
return err
} else {
i = borderRight
p.pointer = oldptr
}
} else if i > 0 && (
p.tokens[i-1].tokenType == gJSON_TOKEN_COMMA ||
p.tokens[i-1].tokenType == gJSON_TOKEN_BRACE_LEFT ||
p.tokens[i-1].tokenType == gJSON_TOKEN_BRACKET_LEFT) {
// json数组操作
oldptr := p.pointer
p.pointer.a = append(p.pointer.a, node)
p.pointer = node
err := p.parseTokenNodeToVar(i + 1, borderRight - 1)
if err != nil {
return err
} else {
i = borderRight
p.pointer = oldptr
}
} else {
// json层级关系
p.pointer = node
err := p.parseTokenNodeToVar(i + 1, borderRight - 1)
if err != nil {
return err
} else {
i = borderRight
}
}
case gJSON_TOKEN_STRING:
fallthrough
case gJSON_TOKEN_NUMBER:
if i > 0 && p.tokens[i-1].tokenType == gJSON_TOKEN_COLON {
k := string(p.tokens[i-2].token)
v := string(p.tokens[i].token)
p.pointer.m[k] = v
} else if p.tokens[i+1].tokenType != gJSON_TOKEN_COLON {
p.pointer.a = append(p.pointer.a, string(p.tokens[i].token))
}
case gJSON_TOKEN_COLON:
if i < 1 || (p.tokens[i-1].tokenType != gJSON_TOKEN_STRING) {
return errors.New(fmt.Sprintf("json parse error: invalid charactar '%s' at index %d", string(p.tokens[i].token), p.tokens[i].tokenindex))
}
case gJSON_TOKEN_COMMA:
if (p.tokens[i+1].tokenType != gJSON_TOKEN_STRING &&
p.tokens[i+1].tokenType != gJSON_TOKEN_NUMBER &&
p.tokens[i+1].tokenType != gJSON_TOKEN_BRACE_LEFT &&
p.tokens[i+1].tokenType != gJSON_TOKEN_BRACKET_LEFT) ||
(i < 1 || (
p.tokens[i-1].tokenType != gJSON_TOKEN_STRING &&
p.tokens[i-1].tokenType != gJSON_TOKEN_NUMBER &&
p.tokens[i-1].tokenType != gJSON_TOKEN_BRACE_RIGHT &&
p.tokens[i-1].tokenType != gJSON_TOKEN_BRACKET_RIGHT)) {
return errors.New(fmt.Sprintf("json parse error: invalid charactar '%s' at index %d", string(p.tokens[i].token), p.tokens[i].tokenindex))
}
}
}
return nil
}
// 打印出所有的token(测试用)
func (p *gJsonParser)printTokens() {
for _, v := range p.tokens {
fmt.Println(string(v.token))
}
}
// 格式化打印根节点
func (p *gJsonParser)Print() {
if len(p.root.m) > 0 {
fmt.Println("{")
} else {
fmt.Println("[")
}
p.printNode(p.pointer, "\t")
if len(p.root.m) > 0 {
fmt.Println("}")
} else {
fmt.Println("]")
}
}
// 格式化打印根节点
func (p *gJsonParser)printNode(n *gJsonNode, indent string) {
if len(n.m) > 0 {
for k, v := range n.m {
if t, ok := v.(*gJsonNode); ok {
if len(t.m) > 0 {
fmt.Printf("%v%v\t: {\n", indent, k)
p.printNode(t, indent + "\t")
fmt.Printf("%v}\n", indent)
} else {
fmt.Printf("%v%v\t: [\n", indent, k)
p.printNode(t, indent + "\t")
fmt.Printf("%v}\n", indent)
}
} else {
fmt.Printf("%v%v\t: %v\n", indent, k, v)
}
}
}
if len(n.a) > 0 {
for k, v := range n.a {
if t, ok := v.(*gJsonNode); ok {
if len(t.m) > 0 {
fmt.Printf("%v%v\t: {\n", indent, k)
p.printNode(t, indent + "\t")
fmt.Printf("%v}\n", indent)
} else {
fmt.Printf("%v%v\t: [\n", indent, k)
p.printNode(t, indent + "\t")
fmt.Printf("%v}\n", indent)
}
} else {
fmt.Printf("%v%v : %v\n", indent, k, v)
}
}
}
}
// 创建一个json数据对象
func newJsonNode() *gJsonNode {
return &gJsonNode {
m: make(map[string]interface{}),
a: make([]interface{}, 0),
}
}

31
g/encoding/gxml/gxml.go Normal file
View File

@ -0,0 +1,31 @@
// Copyright 2017 gf Author(https://gitee.com/johng/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://gitee.com/johng/gf.
// XML
package gxml
import (
"github.com/clbanning/mxj"
)
// 将XML内容解析为map变量
func Decode(xmlbyte []byte) (map[string]interface{}, error) {
return mxj.NewMapXml(xmlbyte)
}
// 将map变量解析为XML格式内容
func Encode(v map[string]interface{}) ([]byte, error) {
return mxj.Map(v).Xml()
}
// XML格式内容直接转换为JSON格式内容
func ToJson(xmlbyte []byte) ([]byte, error) {
if mv, err := mxj.NewMapXml(xmlbyte); err == nil {
return mv.Json()
} else {
return nil, err
}
}

View File

@ -16,7 +16,7 @@ import (
)
const (
gDEFAULT_CONFIG_FILE = "config" // 默认的配置管理文件名称
gDEFAULT_CONFIG_FILE = "config.json" // 默认的配置管理文件名称
)
// 配置管理对象
@ -43,7 +43,7 @@ func (c *Config) filePath(files []string) string {
c.mu.RLock()
fpath := c.path + gfile.Separator + file
c.mu.RUnlock()
return fpath + ".json"
return fpath
}
// 设置配置管理器的配置文件存放目录绝对路径
@ -111,6 +111,14 @@ func (c *Config) GetBool(pattern string, files...string) bool {
return false
}
// 返回指定json中的float32
func (c *Config) GetFloat32(pattern string, files...string) float32 {
if j := c.getJson(files); j != nil {
return j.GetFloat32(pattern)
}
return 0
}
// 返回指定json中的float64
func (c *Config) GetFloat64(pattern string, files...string) float64 {
if j := c.getJson(files); j != nil {
@ -121,10 +129,16 @@ func (c *Config) GetFloat64(pattern string, files...string) float64 {
// 返回指定json中的float64->int
func (c *Config) GetInt(pattern string, files...string) int {
return int(c.GetFloat64(pattern))
if j := c.getJson(files); j != nil {
return j.GetInt(pattern)
}
return 0
}
// 返回指定json中的float64->int64
func (c *Config) GetInt64(pattern string, files...string) int64 {
return int64(c.GetFloat64(pattern))
}
// 返回指定json中的float64->uint
func (c *Config) GetUint(pattern string, files...string) uint {
if j := c.getJson(files); j != nil {
return j.GetUint(pattern)
}
return 0
}

View File

@ -17,7 +17,7 @@ func init () {
Port : "3306",
User : "root",
Pass : "123456",
Name : "test2",
Name : "test",
Type : "mysql",
Role : "master",
Charset : "utf8",
@ -416,7 +416,7 @@ func main() {
//create()
//create()
//insert()
//query()
query()
//replace()
//save()
//batchInsert()

View File

@ -2,8 +2,56 @@ package main
import (
"fmt"
"gitee.com/johng/gf/g/encoding/gxml"
"gitee.com/johng/gf/g/os/gfile"
)
func main() {
fmt.Printf("%b\n", 123)
//json := gfile.GetBinContents("/home/john/Workspace/Go/GOPATH/src/gitee.com/johng/gf/geg/frame/config.json")
//y, err := yaml.JSONToYAML(json)
//fmt.Println(err)
//fmt.Println(string(y))
//
//j, err := yaml.YAMLToJSON(y)
//fmt.Println(err)
//fmt.Println(string(j))
x := `
<?xml version="1.0" encoding="UTF-8"?>
<rss kk-name="1">
<channel>
<title>Comments for 碎言碎语</title>
<atom:link href="http://johng.cn/comments/feed/" rel="self" type="application/rss+xml" />
<link>http://johng.cn</link>
<description></description>
<lastBuildDate>Fri, 05 Jan 2018 02:56:11 +0000</lastBuildDate>
<sy:updatePeriod>hourly</sy:updatePeriod>
<sy:updateFrequency>1</sy:updateFrequency>
<generator>https://wordpress.org/?v=4.7.3</generator>
<item>
<title>Comment on Go性能优化string与[ ]byte转换 by John</title>
<link>http://johng.cn/go-optimize-string-bytes/#comment-114</link>
<dc:creator><![CDATA[John]]></dc:creator>
<pubDate>Fri, 05 Jan 2018 02:56:11 +0000</pubDate>
<guid isPermaLink="false">http://johng.cn/?p=3435#comment-114</guid>
<description><![CDATA[这篇文章我转自雨痕由于string和[]byte之间的转换比较常用所以这篇文章的性能对比才比较惊人。其他基本类型与[]byte这件的转换性能差别不大struct与[]byte的转换性能差别主要在数据结构设计上比如socket通信的话基本都是自己通过二进制转换来组织需要的数据结构。总得来说在go开发的时候尽量多用二进制参数([]byte)是好的。]]></description>
<content:encoded><![CDATA[<p>这篇文章我转自雨痕由于string和[]byte之间的转换比较常用所以这篇文章的性能对比才比较惊人。其他基本类型与[]byte这件的转换性能差别不大struct与[]byte的转换性能差别主要在数据结构设计上比如socket通信的话基本都是自己通过二进制转换来组织需要的数据结构。总得来说在go开发的时候尽量多用二进制参数([]byte)是好的。</p>
]]></content:encoded>
</item>
<item>
<title>Comment on 层次不同的人,是很难沟通的 by buhuipao</title>
<link>http://johng.cn/hard-for-communitication-between-different-levels/#comment-105</link>
<dc:creator><![CDATA[buhuipao]]></dc:creator>
<pubDate>Tue, 19 Sep 2017 09:10:08 +0000</pubDate>
<guid isPermaLink="false">http://johng.cn/?p=2854#comment-105</guid>
<description><![CDATA[博主说得很对,认知很重要。]]></description>
<content:encoded><![CDATA[<p>博主说得很对,认知很重要。</p>
]]></content:encoded>
</item>
</channel>
</rss>`
j, _ := gxml.ToJson([]byte(x))
fmt.Println(string(j))
}