功能说明
通过go修改或者新增PHP配置文件的配置项。支持修改和新增的配置的值为int、float、string、map(对应php中的一维数组和二维数组)
PHP配置格式文件如下:
小试牛刀
go类型检测:
var etcd_value interface{} //必须设置为接口类型,才能进行断言
etcd_value = "666.8"
// etcd_value = map[string]string{"host": "192.168.5.222266", "port": "99", "username": "niubi", "password": "222jjjj"}
switch v := etcd_value.(type) {
case int:
fmt.Println("整数", v)
case string:
fmt.Println("字符串", v)
case float64:
fmt.Println("字符串", v)
case map[string]string:
fmt.Println("哈希", v)
}
用switch进行类型检测并转换为字符串
//识别value类型并转换为字符串
func GetChangeValue(etcd_value interface{}) (string, bool) {
var str string
var isStr bool
switch v := etcd_value.(type) {
case int:
str = strconv.Itoa(v)
case string:
str = v
isStr = true
case bool:
str = strconv.FormatBool(v) //返回"true"或"false"。
case float64:
str = strconv.FormatFloat(v, 'f', -1, 64) //float64转为string类型
case map[string]string:
str = ArrToStr(v)
case map[string]map[string]string:
str = MultiArrToStr(v)
}
return str, isStr
}
str = strconv.FormatFloat(v, 'f', -1, 64) //float64转为string类型
这里第三个参数代表保存的小数位数,-1代表保存所有
//go截取字符串:遵循左闭右开原则
func main() {
word := "helloworld"
find := strings.Index(word, "l")
cut := word[0:find] //截取字符串遵循左闭右开
fmt.Println(find, cut) //输出 2 he
}
最终代码
package updateConf
import (
"fmt"
"io/ioutil"
"log"
"strconv"
"strings"
)
const (
keyHead = "$"
keyCut = ";"
KeyConnectVal = "="
)
//配置文件不包含return的
func ChangeConfV1(path string, change_key string, change_value string, isStr bool) {
bytes, err := ioutil.ReadFile(path)
if err != nil {
log.Fatalln("err:", err)
}
content := string(bytes)
var key_start, key_end, value_start, value_end, real_start_index int
var key_name, key_value string
find := content
isFirst := true
for {
if isFirst {
first_cut := strings.Index(find, keyCut)
if key_start == -1 {
break
}
first := find[:first_cut]
key_start = strings.Index(first, keyHead)
key_end = strings.Index(first, KeyConnectVal)
key_name = first[key_start:key_end]
key_name = strings.TrimSpace(key_name)
find = find[key_end:]
real_start_index += key_end
// =和;之间是key的值
value_start = strings.Index(first, KeyConnectVal)
key_value = first[value_start+1:]
// fmt.Printf("key_name=%s;key_value=%s\n", key_name, key_value)
isFirst = false
}
// fmt.Println("real_start_index", real_start_index)
//判断是否是要修改的key
if key_name == change_key {
replace_start := real_start_index + 1
replace_end := real_start_index + len(key_value) + 1
// fmt.Printf("real value:%s\n", content[replace_start:replace_end])
//将原来的值替换为新值
var b strings.Builder
b.WriteString(content[:replace_start]) //不包括replace_start
b.WriteString(" ")
if isStr {
b.WriteString("'") // 仅针对字符串
}
b.WriteString(change_value)
if isStr {
b.WriteString("'") // 仅针对字符串
}
// b.WriteString("'")
b.WriteString(content[replace_end:]) //包括replace_end(这里应该是分号)
new := b.String()
fmt.Println(new)
// 生成新文件
err := ioutil.WriteFile("./config_new.php", []byte(new), 0777)
if err != nil {
log.Printf("write config file failed. err : %s\n", err)
}
log.Printf("update config success ! update key = %s\n", key_name)
return //跳出整个程序
}
real_start_index = real_start_index + value_end - 1
// real_start_index = real_start_index + value_end + 1
//以;为分隔符。;后面的$为变量的开头
index := strings.Index(find, keyCut)
if index == -1 {
break
}
// fmt.Println("index=", index)
find = find[index:]
real_start_index += index
key_start = strings.Index(find, keyHead)
//如果不包含引号的话,说明已经遍历到最后的配置项了
if key_start == -1 {
break
}
// find = find[key_start:]
key_end = strings.Index(find, KeyConnectVal)
key_name = find[key_start:key_end]
key_name = strings.TrimSpace(key_name)
// fmt.Printf("key_name=%s\n", key_name)
find = find[key_end:]
real_start_index += key_end
// = 和 ; 之间是key的值
value_start = strings.Index(find, KeyConnectVal)
value_end = strings.Index(find, keyCut)
find = find[value_start+1:]
real_start_index = real_start_index + value_start + 1
key_value = find[:value_end-1]
//去除value左右的空格
// key_value = strings.TrimSpace(key_value)
// fmt.Printf("key_name=%s;key_value=%s\n", key_name, key_value)
find = find[value_end-1:]
}
//执行到这里说明原来的配置文件没有匹配到key_name,需要新增配置项
// 找到最后一个分号
lastSlice := strings.LastIndex(content, ";")
if lastSlice == -1 {
return
}
start_part := content[:lastSlice+1]
end_part := content[lastSlice+1:]
fmt.Println("lastslice", lastSlice)
var b strings.Builder
b.WriteString(start_part)
b.WriteString("\n")
b.WriteString(change_key)
b.WriteString(" = ")
if isStr {
b.WriteString("'") // 仅针对字符串
}
b.WriteString(change_value)
if isStr {
b.WriteString("'") // 仅针对字符串
}
b.WriteString(keyCut)
b.WriteString(end_part)
new := b.String()
fmt.Println("new=", new)
// 生成新文件
err = ioutil.WriteFile("./config_new.php", []byte(new), 0777)
if err != nil {
log.Printf("write config file failed. err : %s\n", err)
}
log.Printf("update config success ! insert key = %s\n", key_name)
}
//将数组拼装成字符串(针对一维数组)
func ArrToStr(str map[string]string) string {
var b strings.Builder
b.WriteString("array(\n\t")
for key, val := range str {
b.WriteString("'")
b.WriteString(key)
b.WriteString("'")
b.WriteString(" => ")
b.WriteString("'")
b.WriteString(val)
b.WriteString("'")
b.WriteString(",")
}
b.WriteString("\n)")
arrstr := b.String()
return arrstr
}
//将数组拼装成字符串(针对二维数组)
func MultiArrToStr(str map[string]map[string]string) string {
var b strings.Builder
b.WriteString("array(\n")
for key, val := range str {
b.WriteString("'")
b.WriteString(key)
b.WriteString("'")
b.WriteString(" => ")
b.WriteString("array(\n\t")
for k, v := range val {
b.WriteString("'")
b.WriteString(k)
b.WriteString("'")
b.WriteString(" => ")
b.WriteString("'")
b.WriteString(v)
b.WriteString("'")
b.WriteString(",")
}
b.WriteString("\n)")
b.WriteString(",\n")
}
b.WriteString(")")
arrstr := b.String()
return arrstr
}
//识别value类型并转换为字符串
func GetChangeValue(etcd_value interface{}) (string, bool) {
var str string
var isStr bool
switch v := etcd_value.(type) {
case int:
str = strconv.Itoa(v)
case string:
str = v
isStr = true
case float64:
str = strconv.FormatFloat(v, 'f', -1, 64) //float64转为string类型
case map[string]string:
str = ArrToStr(v)
case map[string]map[string]string:
str = MultiArrToStr(v)
}
return str, isStr
}
func main() {
conf_path := "./config1.php"
change_key := "$slaveofRedis"
var etcd_value interface{} //必须设置为接口类型,才能进行断言
//字符串
// etcd_value = 333
//一维数组
// etcd_value = map[string]string{"host": "192.168.5.222266", "port": "99", "username": "niubi", "password": "222jjjj"}
//二维数组
etcd_value = map[string]map[string]string{
"test1": {"name": "lcj", "age": "22"},
"test2": {"type": "dddd", "hello": "hhhhhh"},
"test3": {"type": "333", "hello": "22222"},
}
change_value, isStr := updateConf.GetChangeValue(etcd_value)
fmt.Printf("v=%v\n", change_value)
updateConf.ChangeConfV1(conf_path, change_key, change_value, isStr)
}