文件如图 已经客观存在 做读写等
思路1-----
package main
import (
"encoding/json"
"log"
"os"
)
const JS_FILE_PATH string = "/home/pi/sgo/my.json"
func WriteToConfig(k string, v interface{}) error {
config_json, err := os.ReadFile(JS_FILE_PATH)
if err != nil {
log.Printf("[Config] Read config.json failed\r\n")
return err
}
var config map[string]interface{}
json.Unmarshal(config_json, &config)
config[k] = v
str, err := json.Marshal(config)
if err != nil {
log.Printf("[Config] json Marshal failed\r\n")
return err
}
log.Printf("[Config] config json : %s\r\n", string(str))
err = os.WriteFile(JS_FILE_PATH, str, 0644)
if err != nil {
log.Printf("[Config] Failed to write config.json, err: %v\r\n", err)
return err
}
return nil
}
func main() {
WriteToConfig("gw_version", "V1.0")
log.Printf("886\r\n")
}
很快就修改了
破坏了JS可读的样式--它是一行的--不是JS那种一行一行分开的--【最好的做法在后面】
思路2----优化上面代码 解决问题
package main
import (
"bytes"
"encoding/json"
"fmt"
"log"
"os"
"runtime"
)
const JS_FILE_PATH string = "/home/pi/sgo/my.json"
func must(action string, err error) {
if err != nil {
panic("failed to " + action + ": " + err.Error())
}
}
func WriteToConfig(k string, v interface{}) error {
_, file, line, ok := runtime.Caller(1)
fmt.Println(file, line, ok)
config_json, err := os.ReadFile(JS_FILE_PATH)
must("ReadFile", err)
var config map[string]interface{}
json.Unmarshal(config_json, &config) //解析出来
config[k] = v //替换
str, err := json.Marshal(config) //还原JS
must("Marshal", err)
//如何维持JS原来的样子 参考https://www.cnblogs.com/ayanmw/p/8677453.html
var out bytes.Buffer //一个数据结构
err = json.Indent(&out, str, "", " ")
jsstring := out.String()//bytes.Buffer转为String
log.Printf("[Config] config json : %s\r\n", string(str))
err = os.WriteFile(JS_FILE_PATH, []byte(jsstring), 0644)//String转为[]byte
must("WriteFile", err)
return nil
}
func main() {
WriteToConfig("gw_version", "V2.1")
log.Printf("886\r\n")
}
继续
如果说goroutine和channel是Go并发的两大基石,
那么接口是Go语言编程中数据类型的关键。
这里我们做的很简单
是为了可以掺入不同的参数 string int
++++++++++++++黄金段位做法+++++++++++++++
看到VIP你就知道viper不是浪得虚名了 github看到很多人在使用 我自己试一试
它就是专门处理这种事情的
GO就是少自己写 多用包!
比如现在文件关系如图
我修改my.js文件
{
"ble_max_conn": 2,
"ble_name": "M_IZAR_TEST",
"gw_version": "V2.1"
}
my.json
加入配置文件如上 代码
package main
import (
"fmt"
"github.com/spf13/viper"
)
func InitConfig() {
viper.SetConfigName("my") //找寻文件的名字[my.json]
viper.SetConfigType("json") // 找寻文件的类型
viper.AddConfigPath(".") //.代表当前文件夹找寻,可以多个目录找寻,生成数组
err := viper.ReadInConfig() //读取配置文件
if err != nil {
if v, ok := err.(viper.ConfigFileNotFoundError); ok {
fmt.Println(v)
} else {
panic(fmt.Errorf("read config err=%s", err))
}
}
}
func main() {
InitConfig()
ble_max_conn := viper.GetInt("ble_max_conn")
ble_name := viper.GetString("ble_name")
gw_version := viper.GetString("gw_version")
fmt.Println("Get Config")
fmt.Println(ble_max_conn, ble_name, gw_version)
viper.Set("ble_max_conn", 6)
viper.Set("ble_name", "M_KOSON")
viper.Set("gw_version", "V2.0")
viper.WriteConfig() //重写文件
}
非常湿滑
上面的代码还可以简化 不需要调用I开头的Init
神奇函数 init是不需要调用的 是在main之前就调用的
修改为
增加一个 监控文件变化 需要增加一个包
计划是 手动远程修改文件 看看程序的log
发现我修改int 会不对 但是log有
package main
import (
"fmt"
"time"
"github.com/spf13/viper"
"github.com/fsnotify/fsnotify"
)
func init() {
viper.SetConfigName("my")
viper.SetConfigType("json")
viper.AddConfigPath(".")
err := viper.ReadInConfig()
if err != nil {
if v, ok := err.(viper.ConfigFileNotFoundError); ok {
fmt.Println(v)
} else {
panic(fmt.Errorf("read config err=%s", err))
}
}
}
func main() {
ble_max_conn := viper.GetInt("ble_max_conn")
ble_name := viper.GetString("ble_name")
gw_version := viper.GetString("gw_version")
fmt.Println("Get Config")
fmt.Println(ble_max_conn, ble_name, gw_version)
viper.Set("ble_max_conn", 6)
viper.Set("ble_name", "M_KOSON")
viper.Set("gw_version", "V2.0")
viper.WriteConfig()
viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
fmt.Printf("file changed:%s %d\r\n", e.Name,viper.GetInt("ble_max_conn"))
})
for{
time.Sleep(time.Second * 100)
}
}
继续:
完成这样一个逻辑 本地有没有my.jsio文件 有的话就读出来看一看没有的话就自动创建文件 写default的值 后面的流程一样 监控这个文件的变化
完美答案 只用viper!!!不要使用JS了!!!
package main
import (
"fmt"
"github.com/spf13/viper"
)
func init() {
viper.SetConfigName("my")
viper.SetConfigFile("./my.json")
viper.AddConfigPath(".")
viper.SetConfigType("json")
err := viper.ReadInConfig()
if err != nil {
if v, ok := err.(viper.ConfigFileNotFoundError); ok {
fmt.Println(v)
} else {
fmt.Println(err) //no file in u pc
Setdefault() //creat file
viper.ReadInConfig() //get viper data again ,as have file
}
}
}
func Setdefault() error {
viper.Set("ble_max_conn", 6)
viper.Set("ble_name", "M_KOSON")
viper.Set("gw_version", "V2.0")
err := viper.WriteConfig() //重写文件
if err != nil {
fmt.Println("Setdefault Fail")
}
fmt.Println("Setdefault Ok")
return nil
}
func main() {
ble_max_conn := viper.GetInt("ble_max_conn")
ble_name := viper.GetString("ble_name")
gw_version := viper.GetString("gw_version")
fmt.Println("Get Config")
fmt.Println(ble_max_conn, ble_name, gw_version)
}
上面简洁 台湾的函数名字叫做RESET它的做法没有viper好用 出来的文件也不好看!对比
func Setdefault() error {
viper.Set("ble_max_conn", 6)
viper.Set("ble_name", "M_KOSON")
viper.Set("gw_version", "V2.0")
err := viper.WriteConfig() //重写文件
if err != nil {
fmt.Println("Setdefault Ok")
}
return nil
}
func Reset() error {
config := make(map[string]interface{})
config["ble_max_conn"] = 1
config["ble_name"] = "KOSON"
config["gw_version"] = "V1.0"
str, _ := json.Marshal(config)
log.Printf("[Config] config json : %s\r\n", string(str))
err := os.WriteFile("./my.json", str, 0644)
if err != nil {
log.Printf("[Config] Failed to write config.json, err: %v\r\n", err)
return err
}
return nil
}
继续黄金做法 还可以简化 它是set KV以后还需要读一次 其实可以不读的!
最后的代码
package main
import (
"fmt"
"github.com/spf13/viper"
)
func init() {
viper.SetConfigName("my")
viper.SetConfigFile("./my.json")
viper.AddConfigPath(".")
viper.SetConfigType("json")
err := viper.ReadInConfig()
if err != nil {
if v, ok := err.(viper.ConfigFileNotFoundError); ok {
fmt.Println(v)
} else {
fmt.Println(err) //no file in u pc
Setdefault() //creat file
}
}
}
func Setdefault() error {
viper.SetDefault("ble_max_conn", 6)
viper.SetDefault("ble_name", "M_KOSON")
viper.SetDefault("gw_version", "V2.0")
err := viper.WriteConfig()
if err != nil {
fmt.Println("Setdefault Fail")
}
fmt.Println("Setdefault Ok")
return nil
}
func main() {
ble_max_conn := viper.GetInt("ble_max_conn")
ble_name := viper.GetString("ble_name")
gw_version := viper.GetString("gw_version")
fmt.Println("Get Config")
fmt.Println(ble_max_conn, ble_name, gw_version)
}