For Java there is the Properties class that offers functionality to parse / interact with property file.
Is there something similar in golang standard library ?
If not, what other alternatives do I have ?
See standart library https://golang.org/pkg/os/#FileInfo
type FileInfo interface {
Name() string // base name of the file
Size() int64 // length in bytes for regular files; system-dependent for others
Mode() FileMode // file mode bits
ModTime() time.Time // modification time
IsDir() bool // abbreviation for Mode().IsDir()
Sys() interface{} // underlying data source (can return nil)
}
If your properties file uses TOML then you can use the TOML parser from https://github.com/BurntSushi/toml. Here is an example I did that parses a "properties file" for me Properties file content(properties.ini)
dbpassword="password"
database="localhost"
dbuser="user"
Code that is parsing the properties file
package main
import (
"fmt"
"log"
"os"
"github.com/BurntSushi/toml"
)
// Config ...
type Config struct {
Dbpassword string
Database string
DbUser string
}
// Reads info from config file
func ReadConfig() Config {
var configfile = "properties.ini"
_, err := os.Stat(configfile)
if err != nil {
log.Fatal("Config file is missing: ", configfile)
}
var config Config
if _, err := toml.DecodeFile(configfile, &config); err != nil {
log.Fatal(err)
}
//log.Print(config.Index)
return config
}
func main() {
config := ReadConfig()
fmt.Printf("%s: %s: %s
", config.Dbpassword, config.Database, config.DbUser)
}
Output:
password: localhost: user
From your question, it's not clear whether you want to parse some existing properties file(s) or you're merely interested in general approaches to have your Go program consume configuration presented in some textual form.
If you want the former, then @icza
pointed you to the right direction: there exists at least one 3rd-party Go package which implements parsing of the Java properties files.
If you want the latter, there are lots of solutions to pick from:
The standard library has packages to parse XML and JSON-formatted data streams.
There exists a host of 3rd-party libraries to read INI-style files. A library exists which allows reading "hierarchical" INI files—with nested sections (Git configuration style).
There exist 3rd-party libraries which parse custom textual formats such as YAML and TOML.
Finally, there exist "integrated" solutions which provide for pulling bits of configuration from different sources simultaneously: the environment, the configuration files and the command-line options; https://github.com/spf13/viper is a good example of them.
TL;DR
Think through your goals, do your research, take your pick.
You can use this following code Instead of using 3rd Party libs
package main
import (
"bufio"
"fmt"
"io"
"os"
"strings"
)
type Config map[string]string
func ReadConfig(filename string) (Config, error) {
// init with some bogus data
config := Config{
"port": "8888",
"password": "abc123",
"ip": "127.0.0.1",
}
if len(filename) == 0 {
return config, nil
}
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()
reader := bufio.NewReader(file)
for {
line, err := reader.ReadString('
')
// check if the line has = sign
// and process the line. Ignore the rest.
if equal := strings.Index(line, "="); equal >= 0 {
if key := strings.TrimSpace(line[:equal]); len(key) > 0 {
value := ""
if len(line) > equal {
value = strings.TrimSpace(line[equal+1:])
}
// assign the config map
config[key] = value
}
}
if err == io.EOF {
break
}
if err != nil {
return nil, err
}
}
return config, nil
}
func main() {
// for this tutorial, we will hard code it to config.txt
config, err := ReadConfig(`C:\Users\mseelam.ORADEV\GoglandProjects\MyFirstProj\data\config`)
if err != nil {
fmt.Println(err)
}
//fmt.Println("Config data dump :", config)
// assign values from config file to variables
ip := config["ip"]
pass := config["pass"]
port := config["port"]
fmt.Println("IP :", ip)
fmt.Println("Port :", port)
fmt.Println("Password :", pass)
}
Adding on top of @Madhu's answer, you can create a very simple package to read a properties file using Scanner, and read line by line of your file skipping invalid lines (those not having the '=' char):
Example:
package fileutil
import (
"bufio"
"os"
"strings"
"log"
)
type AppConfigProperties map[string]string
func ReadPropertiesFile(filename string) (AppConfigProperties, error) {
config := AppConfigProperties{}
if len(filename) == 0 {
return config, nil
}
file, err := os.Open(filename)
if err != nil {
log.Fatal(err)
return nil, err
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
if equal := strings.Index(line, "="); equal >= 0 {
if key := strings.TrimSpace(line[:equal]); len(key) > 0 {
value := ""
if len(line) > equal {
value = strings.TrimSpace(line[equal+1:])
}
config[key] = value
}
}
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
return nil, err
}
return config, nil
}
Sample test sample_test.properties :
host=localhost
proxyHost=test
protocol=https://
chunk=
Properties test:
package fileutil
import (
"testing"
)
func TestReadPropertiesFile(t *testing.T) {
props, err := ReadPropertiesFile("sample_test.properties")
if err != nil {
t.Error("Error while reading properties file")
}
if props["host"] != "localhost" || props["proxyHost"] != "test" || props["protocol"] != "https://" || props["chunk"] != "" {
t.Error("Error properties not loaded correctly")
}
}