相信對於很多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 專案為什麼要配置檔案
對於很多配置相關的項如監聽的埠、資料庫的地址、埠等會比較適合放在配置中,而不是硬編碼在程式碼中,因此配置檔案的使用還是比較常見的。 對於使用什麼型別的配置檔案大家不需要糾結,根據需求就好了,
配置檔案需要應對的幾種場景
- IDE執行/除錯時期讀取配置檔案
- 執行單測或者benchmark Test的時候讀取配置檔案
- 可執行檔案(部署檔案)讀取配置檔案
- 專案中需要僅使用一個配置檔案,配置檔案可以在以上三種情況下都可以被正常讀取
配置檔案的放置
一般配置檔案會放在專案的根目錄或者比較明顯的位置,當然對於Golang我個人還是比較推薦放在專案的根目錄, 當然放在其他目錄也不是不可以,但可能比較麻煩。
怎麼滿足配置檔案需要應對的幾種場景?
- 從專案可執行檔案目錄讀取配置檔案, 例項程式碼如下:
// 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
}
複製程式碼
- 從原始碼檔案所在目錄遞迴往上層目錄尋找
// 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
作為依賴管理工具
支援的格式
- yaml格式
- 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()
}
}
複製程式碼
你只需要定義自己需要的配置結構, 指定檔名稱即可正確讀取到配置, 使用起來也非常簡單, 推薦放在專案的根目錄
讀取順序規則
- 先從可執行檔案的執行目錄讀取配置檔案
- 如果讀取不到則從專案的原始碼所在目錄讀取, 如果讀取不到,則遞迴往根目錄查詢,直到根目錄為止
- 找不到配置檔案則會丟擲錯誤,找到則不會返回任何錯誤
寫在最後
golang 的配置檔案處理方式或許還有很多種,所以如果大家有其他比較好的法子也可以分享出來大家一起學習一起進步. 如有任何疑問,歡迎在下方留言評論,或者到上面我專案地址中去提issue.
此文如有轉載,請勿修改原文內容.