嵌入式linux之go语言开发(十二)参数配置文件存储模块开发

简介: 嵌入式linux之go语言开发(十二)参数配置文件存储模块开发

参数配置和存储是经常用到的功能。


比如常用的可以用json文件,XML文件,或INI文件,YAML文件,properties文件等存储配置信息。


但是,这些都不够简单。


我想要的简单有多简单呢?整个互联网上没有比这更简单好用的。


例如,我想保存个IP地址和端口参数。理想是这样的:


syscfg.ip = "218.28.133.181"


syscfg.port = 22288


syscfg.saveCfg()


就这几步,就把需要的参数持久化的存储起来了。开机只需要syscfg.load() 就完成了配置信息的加载。


比起其他的方式,是不是没有比这更简单了。即便是小白,立马也会用。


之前在Android和嵌入式c上,都已封装好的有这样的功能很好用。


Android上的封装,参见:https://blog.csdn.net/yyz_1987/article/details/104122764


但是在go语言这块儿,计划也打造一个这样的参数配置存储的功能。


即使其他维护的人不懂yaml,不懂xml,不懂json解析,没关系,这种封装后谁都很快会用。


这样的好处是什么呢?这样实际上也是一种模块化和分层的思想。让应用层的人不关心底层是如何实现的。


有的说直接操作json或gob也很简单啊,几行代码而已。但是,如果哪天说想让你换种存储方式,应用里每处要扒拉改一遍吗?


再比如假如对配置文件分分类,有N多个配置文件要存储,要写N遍的解析json,加载json的方法吗?


好的封装可以做到事半功倍。


以下为简单的实现:


代码看着是有点儿长,其实这里面BaseConf以及它的相关操作代码可以单独抽出来。


package main
import (
  "bufio"
  "encoding/json"
  "fmt"
  "io"
  "os"
  "reflect"
  "strings"
)
// BaseConf 配置文件操作的基础封装
type BaseConf struct {
}
// OthCfg 配置文件1
type OthCfg struct {
  BaseConf
  IP   string
  Port int
}
// SysCfg 配置文件2
type SysCfg struct {
  BaseConf
  Name string
  Age  int
}
// Save ...
func (cfg *BaseConf) Save(v interface{}) {
  t := reflect.TypeOf(v)
  fname := fmt.Sprintf("%s.json", t)
  fname = strings.Replace(fname, "*", "r", -1)
  fmt.Println(t)
  fmt.Println(fname)
  //fmt.Printf("type of is:%v\n", t)
  jsond, err := json.Marshal(v)
  if err != nil {
    fmt.Println("生成json字符串错误")
  }
  fmt.Println(string(jsond))
  SaveFile(fname, jsond)
}
// Load ...
func (cfg *BaseConf) Load(v interface{}) {
  t := reflect.TypeOf(v)
  fname := fmt.Sprintf("%s.json", t)
  fname = strings.Replace(fname, "*", "r", -1)
  data, err := ReadFile(fname)
  if err != nil {
    fmt.Println(err)
    return
  }
  err = json.Unmarshal(data, v)
  if err != nil {
    fmt.Println(err)
  }
  fmt.Println(v)
}
// SaveFile 存文件
func SaveFile(filename string, data []byte) error {
  fi, err := os.Create(filename)
  if err != nil {
    fmt.Println(err)
    return err
  }
  defer fi.Close()
  w := bufio.NewWriter(fi)
  w.WriteString(string(data))
  w.Flush()
  return nil
}
// ReadFile 读文件
func ReadFile(filename string) ([]byte, error) {
  fi, err := os.Open(filename)
  if err != nil {
    return nil, err
  }
  defer fi.Close()
  r := bufio.NewReader(fi)
  var data []byte
  buf := make([]byte, 1024)
  for {
    n, err := r.Read(buf)
    if err != nil && err != io.EOF {
      return nil, err
    }
    if 0 == n {
      break
    }
    data = append(data, buf[:n]...)
  }
  return data, nil
}
var sysCfg SysCfg
func main() {
  fmt.Println("Hello Go")
  sysCfg.Load(&sysCfg)
  //sysCfg.Name = "yang"
  //sysCfg.Age = 21
  //sysCfg.Save(&sysCfg)
  oth := OthCfg{}
  oth.IP = "192.168.1.97"
  oth.Port = 5057
  oth.Save(&oth)
}


而实际使用者有多简单呢?不用关系底层是什么存储,文件是什么名字。


使用者,即便有多个配置文件要存储,只需要像这样子:


package main
import (
  "fmt"
    "testconfig/config"
)
// OthCfg 配置文件1
type OthCfg struct {
  BaseConf
  IP   string
  Port int
}
// SysCfg 配置文件2
type SysCfg struct {
  BaseConf
  Name string
  Age  int
}
var sysCfg SysCfg
func main() {
  fmt.Println("Hello Go")
  //sysCfg.Load()
  sysCfg.Name = "yang"
  sysCfg.Age = 21
  sysCfg.Save(&sysCfg)
  oth := OthCfg{}
  oth.IP = "192.168.1.97"
  oth.Port = 5057
  oth.Save(&oth)
}


唯一有点儿遗憾的是,你在操作Save的时候,必须把对应的自己传进去才行,不能传错了。


比如oth.Save(&oth) ,若搞成 oth.Save(&sysCfg)会是什么情况?


有没更好的办法?让实例化时就传进来呢?让使用者可以直接调用个oth.Save()即可。


有办法吗?欢迎讨论


最后感谢网友雨痕大神给出的解决方案。


雨痕,《go语言学习笔记》一书的作者。在这里推荐下他的书。真不错,讲的很细致。


他的解决办法如下:





另外发现一很有意思的事情,,有人知道原因吗?


如果把里面conf改为大写,则不行,还必须用小写


sysCfg.BaseConf.conf ,里面是 小写的conf正确


一个大小写,区别就这么大。


有时候学习劲头来了,挡都挡不住,本来问题解决了,但我就想搞明白,刨根究底。这问题影响我晚上没睡好觉。


不过最后还是想明白了。其实那地方为什么必须是小写,原因很简单啊,并没有什么玄机。



最后放出运行没问题的代码:


package main
import (
  "bufio"
  "encoding/json"
  "fmt"
  "io"
  "os"
  "reflect"
  "strings"
)
// IConf 组合模式,父类 定义一个 接口
type IConf interface{
  Save()
  Load()
}
// BaseConf 配置文件操作的基础封装
type BaseConf struct {
  conf IConf
}
// OthCfg 配置文件1
type OthCfg struct {
  BaseConf
  IP   string
  Port int
}
// SysCfg 配置文件2
type SysCfg struct {
  BaseConf
  Name string
  Age  int
}
// Save ...
func (cfg *BaseConf) Save() {
  t := reflect.TypeOf(cfg.conf)
  fname := fmt.Sprintf("%s.json", t)
  fname = strings.Replace(fname, "*", "r", -1)
  fmt.Println(t)
  fmt.Println(fname)
  //fmt.Println(cfg.Conf)
  //fmt.Printf("type of is:%v\n", t)
  jsond, err := json.Marshal(cfg.conf)
  if err != nil {
    fmt.Println("生成json字符串错误")
  }
  fmt.Println(string(jsond))
  SaveFile(fname, jsond)
}
// Load ...
func (cfg *BaseConf) Load() {
  t := reflect.TypeOf(cfg.conf)
  fname := fmt.Sprintf("%s.json", t)
  fname = strings.Replace(fname, "*", "r", -1)
  fmt.Println(cfg.conf)
  data, err := ReadFile(fname)
  if err != nil {
    fmt.Println(err)
    return
  }
  err = json.Unmarshal(data, cfg.conf)
  if err != nil {
    fmt.Println(err)
  }
  fmt.Println(cfg)
}
// SaveFile 存文件
func SaveFile(filename string, data []byte) error {
  fi, err := os.Create(filename)
  if err != nil {
    fmt.Println(err)
    return err
  }
  defer fi.Close()
  w := bufio.NewWriter(fi)
  w.WriteString(string(data))
  w.Flush()
  return nil
}
// ReadFile 读文件
func ReadFile(filename string) ([]byte, error) {
  fi, err := os.Open(filename)
  if err != nil {
    return nil, err
  }
  defer fi.Close()
  r := bufio.NewReader(fi)
  var data []byte
  buf := make([]byte, 1024)
  for {
    n, err := r.Read(buf)
    if err != nil && err != io.EOF {
      return nil, err
    }
    if 0 == n {
      break
    }
    data = append(data, buf[:n]...)
  }
  return data, nil
}
var sysCfg SysCfg
func main() {
  fmt.Println("Hello Go")
  //sysCfg.BaseConf.Conf = &sysCfg
  //sysCfg.Load()
  //fmt.Println(sysCfg)
  sysCfg.BaseConf.conf = &sysCfg
  sysCfg.Name = "yang"
  sysCfg.Age = 188
  sysCfg.Save()
  sysCfg.Load()
  fmt.Println(sysCfg)
  //sysCfg.Save(&sysCfg)
  // oth := OthCfg{}
  // oth.Conf = &oth
  // oth.IP = "192.168.1.97"
  // oth.Port = 5057
  // oth.Save()
}


相关文章
|
5月前
|
开发框架 JSON 中间件
Go语言Web开发框架实践:路由、中间件、参数校验
Gin框架以其极简风格、强大路由管理、灵活中间件机制及参数绑定校验系统著称。本文详解其核心功能:1) 路由管理,支持分组与路径参数;2) 中间件机制,实现全局与局部控制;3) 参数绑定,涵盖多种来源;4) 结构体绑定与字段校验,确保数据合法性;5) 自定义校验器扩展功能;6) 统一错误处理提升用户体验。Gin以清晰模块化、流程可控及自动化校验等优势,成为开发者的优选工具。
|
6月前
|
Ubuntu 搜索推荐 Linux
详解Ubuntu的strings与grep命令:Linux开发的实用工具。
这就是Ubuntu中的strings和grep命令,透明且强大。我希望你喜欢这个神奇的世界,并能在你的Linux开发旅程上,通过它们找到你的方向。记住,你的电脑是你的舞台,在上面你可以做任何你想做的事,只要你敢于尝试。
367 32
|
8月前
|
JavaScript Linux 网络安全
Termux安卓终端美化与开发实战:从下载到插件优化,小白也能玩转Linux
Termux是一款安卓平台上的开源终端模拟器,支持apt包管理、SSH连接及Python/Node.js/C++开发环境搭建,被誉为“手机上的Linux系统”。其特点包括零ROOT权限、跨平台开发和强大扩展性。本文详细介绍其安装准备、基础与高级环境配置、必备插件推荐、常见问题解决方法以及延伸学习资源,帮助用户充分利用Termux进行开发与学习。适用于Android 7+设备,原创内容转载请注明来源。
1941 77
|
11月前
|
开发框架 Go 计算机视觉
纯Go语言开发人脸检测、瞳孔/眼睛定位与面部特征检测插件-助力GoFly快速开发框架
开发纯go插件的原因是因为目前 Go 生态系统中几乎所有现有的人脸检测解决方案都是纯粹绑定到一些 C/C++ 库,如 OpenCV 或 dlib,但通过 cgo 调用 C 程序会引入巨大的延迟,并在性能方面产生显著的权衡。此外,在许多情况下,在各种平台上安装 OpenCV 是很麻烦的。使用纯Go开发的插件不仅在开发时方便,在项目部署和项目维护也能省很多时间精力。
292 5
|
Go 数据安全/隐私保护 开发者
Go语言开发
【10月更文挑战第26天】Go语言开发
166 3
|
Java 程序员 Go
Go语言的开发
【10月更文挑战第25天】Go语言的开发
132 3
|
11月前
|
Go 数据安全/隐私保护 UED
优化Go语言中的网络连接:设置代理超时参数
优化Go语言中的网络连接:设置代理超时参数
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
436 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
Go to Learn Go之命令行参数
Go to Learn Go之命令行参数
134 8
|
Java Linux API
Linux设备驱动开发详解2
Linux设备驱动开发详解
199 6