Golang 專案之配置檔案
相信對於很多gopher 而言, 我這篇文章,算比較初級,我是一個一年多經驗的golang程式員,有著5年左右的程式設計經驗。
golang 對於初學者還算友好, 寫程式碼很好入門, 但業界對於golang工程與專案的BP卻比較缺少,或者是有很多方為此爭論不休,就比依賴管理工具就搞出了許多個,如 知名的有dep
,vgo
和golang 官方的go module
, 也可能是我所知有限的緣故, 希望大家不吝賜教。
既然要說go專案的配置檔案,那對於配置檔案先做一個簡單的介紹:
配置檔案的格式
yaml
yaml是最近很流行的一種描述語言,上手比較簡單學習成本低,結構清晰, 5分鐘即可掌握所有細節ofollow,noindex">阮一峰老師的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 getgithub.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"` Portint`yaml:"dbPort"` } type TestMyConf struct { Mysql TestIniConf `ini:"mysql"` Namestring`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() } } 複製程式碼
你只需要定義自己需要的配置結構, 指定檔名稱即可正確讀取到配置, 使用起來也非常簡單, 推薦放在專案的根目錄
讀取順序規則
- 先從可執行檔案的執行目錄讀取配置檔案
- 如果讀取不到則從專案的原始碼所在目錄讀取, 如果讀取不到,則遞迴往根目錄查詢,直到根目錄為止
- 找不到配置檔案則會丟擲錯誤,找到則不會返回任何錯誤