Golang 项目之配置文件

10,284 阅读4分钟

相信对于很多gopher 而言, 我这篇文章,算比较初级,我是一个一年多经验的golang程序员,有着5年左右的编程经验。 golang 对于初学者还算友好, 写代码很好入门, 但业界对于golang工程与项目的BP却比较缺少,或者是有很多方为此争论不休,就比依赖管理工具就搞出了许多个,如 知名的有dep, vgo和golang 官方的 go module, 也可能是我所知有限的缘故, 希望大家不吝赐教。

既然要说go项目的配置文件,那对于配置文件先做一个简单的介绍:

配置文件的格式

yaml

yaml是最近很流行的一种描述语言,上手比较简单学习成本低,结构清晰, 5分钟即可掌握所有细节 阮一峰老师的yaml语法教程 一个简单的示例如下:

database:
    addr: localhost
    port: 3306
    username: testuser
    password: abcdef
listen:80

ini

ini 文件也是一个比较常见的配置文件的格式,也是几乎不需要学习成本的,比较简单,只有两个概念 区块与键值对, 但表达能力比较有限,格式如下:

[database]
addr = localhost
port = 3306

[web]
listen = 80

json

json 是一种非常流行的描述语言,表述能力也非常强,非常直观,通常也是不需要什么学习成本的, 常见的格式如下:

{
    "database":{
        "database":"localhost",
        "port":3306
    },
    "web":{
        "listen":80
    }
}

properties

properties 文件对于很多Java程序员应该不陌生,因为在很多spring项目中, 会经常见到这种文件,当然没有用到过的夜别打我,这种完全看兴趣爱好的, 一个简单的文件格式如下:

addr=localhost
port=3306

Golang 的配置文件

golang 项目为什么要配置文件

对于很多配置相关的项如监听的端口、数据库的地址、端口等会比较适合放在配置中,而不是硬编码在代码中,因此配置文件的使用还是比较常见的。 对于使用什么类型的配置文件大家不需要纠结,根据需求就好了,

配置文件需要应对的几种场景

  1. IDE运行/调试时期读取配置文件
  2. 运行单测或者benchmark Test的时候读取配置文件
  3. 可执行文件(部署文件)读取配置文件
  4. 项目中需要仅使用一个配置文件,配置文件可以在以上三种情况下都可以被正常读取

配置文件的放置

一般配置文件会放在项目的根目录或者比较明显的位置,当然对于Golang我个人还是比较推荐放在项目的根目录, 当然放在其他目录也不是不可以,但可能比较麻烦。

怎么满足配置文件需要应对的几种场景?

  1. 从项目可执行文件目录读取配置文件, 实例代码如下:
// get config file from where the executables lies
func getConfigFileFromExecutable(fileName string) *os.File {
	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		return nil
	}
	f, err := os.Open(path.Join(dir, fileName))
	if err != nil {
		return nil
	}
	return f
}
  1. 从源代码文件所在目录递归往上层目录寻找
// read config file
func TestReadConfigFile(t *testing.T) {
	if _, fileNameWithPath, _, ok := runtime.Caller(1); ok {
		d := ReadConfigFile(testFileName, fileNameWithPath)
		if d == nil {
			t.FailNow()
		}
	}
}

这个实现的关键点在于 runtime.Caller(1), 此函数可以返回源代码所在目录,但根据参数的不同,对于调用的位置要求也不同,这里设置的刚好可以满足放在项目根目录的需求

一个开源项目

项目地址喜欢的话点个赞(star), 有问题的话可以提issue. 以联系我。

获取的方式如下

go get  github.com/winjeg/goconf

此项目采用go module作为依赖管理方式,但也兼容于传统的dep作为依赖管理工具 支持的格式

  1. yaml格式
  2. ini 格式

使用实例

package goconf

import (
	"strings"
	"testing"
)

const (
	testYmlFile = "test.yaml"
	testIniFile = "test.ini"

	host = "10.1.1.1"
	port = 3306
	testName = "tom"
)

type TestYmlConf struct {
	DbAddr string `yaml:"dbAddr"`
	Port   int    `yaml:"dbPort"`
}

type TestMyConf struct {
	Mysql TestIniConf `ini:"mysql"`
	Name  string      `ini:"name"`
}

type TestIniConf struct {
	Host string `ini:"host"`
	Port int    `ini:"port"`
}

func TestYaml2Object(t *testing.T) {
	var x TestYmlConf
	err := Yaml2Object(testYmlFile, &x)
	if err != nil {
		t.FailNow()
	}
	if !strings.EqualFold(x.DbAddr, host) || x.Port != port {
		t.FailNow()
	}
}

func TestIni2Object(t *testing.T) {
	var x TestMyConf
	err := Ini2Object(testIniFile, &x)
	if err != nil {
		t.FailNow()
	}
	if !strings.EqualFold(x.Mysql.Host, host) || x.Mysql.Port != port || !strings.EqualFold(testName, x.Name) {
		t.FailNow()
	}
}

你只需要定义自己需要的配置结构, 指定文件名称即可正确读取到配置, 使用起来也非常简单, 推荐放在项目的根目录

读取顺序规则

  1. 先从可执行文件的运行目录读取配置文件
  2. 如果读取不到则从项目的源代码所在目录读取, 如果读取不到,则递归往根目录查找,直到根目录为止
  3. 找不到配置文件则会抛出错误,找到则不会返回任何错误

写在最后

golang 的配置文件处理方式或许还有很多种,所以如果大家有其他比较好的法子也可以分享出来大家一起学习一起进步. 如有任何疑问,欢迎在下方留言评论,或者到上面我项目地址中去提issue.

此文如有转载,请勿修改原文内容.