Введение
ini — это распространенный формат файла конфигурации в Windows. Версия MySQL для Windows использует формат ini для хранения конфигурации.go-ini— это сторонняя библиотека для работы с ini-файлами на языке Go.
Эта статья представляетgo-iniИспользуя библиотеку.
быстрый в использовании
go-ini — это сторонняя библиотека, которую необходимо установить перед использованием:
$ go get gopkg.in/ini.v1
Вы также можете использовать репозиторий на GitHub:
$ go get github.com/go-ini/ini
Сначала создайтеmy.iniКонфигурационный файл:
app_name = awesome web
# possible values: DEBUG, INFO, WARNING, ERROR, FATAL
log_level = DEBUG
[mysql]
ip = 127.0.0.1
port = 3306
user = dj
password = 123456
database = awesome
[redis]
ip = 127.0.0.1
port = 6381
Используйте библиотеку go-ini для чтения:
package main
import (
"fmt"
"log"
"gopkg.in/ini.v1"
)
func main() {
cfg, err := ini.Load("my.ini")
if err != nil {
log.Fatal("Fail to read file: ", err)
}
fmt.Println("App Name:", cfg.Section("").Key("app_name").String())
fmt.Println("Log Level:", cfg.Section("").Key("log_level").String())
fmt.Println("MySQL IP:", cfg.Section("mysql").Key("ip").String())
mysqlPort, err := cfg.Section("mysql").Key("port").Int()
if err != nil {
log.Fatal(err)
}
fmt.Println("MySQL Port:", mysqlPort)
fmt.Println("MySQL User:", cfg.Section("mysql").Key("user").String())
fmt.Println("MySQL Password:", cfg.Section("mysql").Key("password").String())
fmt.Println("MySQL Database:", cfg.Section("mysql").Key("database").String())
fmt.Println("Redis IP:", cfg.Section("redis").Key("ip").String())
redisPort, err := cfg.Section("redis").Key("port").Int()
if err != nil {
log.Fatal(err)
}
fmt.Println("Redis Port:", redisPort)
}
В ini-файле каждая пара ключ-значение занимает одну строку, используя среднюю=разделены. от#Содержимое в начале представляет собой комментарий. ini файлы организованы в разделы.
перегородка с[name]Начало, конец перед следующим разделом. Все содержимое перед разделом принадлежит разделу по умолчанию, напримерmy.iniв файлеapp_nameиlog_level.
использоватьgo-iniШаги для чтения файла конфигурации следующие:
- первый звонок
ini.LoadЗагрузите файл и получите объект конфигурацииcfg; - Затем вызовите объект конфигурации
Sectionметод для получения соответствующего объекта разделаsection, имя раздела по умолчанию"", вы также можете использоватьini.DefaultSection; - Клавиши, чтобы вызвать объект раздела
Keyспособ получения соответствующего элемента конфигурацииkeyобъект; - Поскольку считанные файлы являются строками,
keyОбъект должен вызвать соответствующий метод в соответствии с типом, чтобы вернуть значение определенного типа, например, вышеString,MustIntметод.
Запустите следующую программу, чтобы получить вывод:
App Name: awesome web
Log Level: DEBUG
MySQL IP: 127.0.0.1
MySQL Port: 3306
MySQL User: dj
MySQL Password: 123456
MySQL Database: awesome
Redis IP: 127.0.0.1
Redis Port: 6381
Все строки хранятся в файле конфигурации, поэтому элемент конфигурации, тип которого является строкой, не подведет преобразование типа, поэтомуString()Метод просто возвращает значение.
но если типInt/Uint/Float64В это время преобразование может завершиться ошибкой. такInt()/Uint()/Float64()Возвращает значение и ошибку.
Остерегайтесь этого несоответствия! Если мы изменим порт redis в конфигурации на недопустимый номер x6381, работающая программа сообщит об ошибке:
2020/01/14 22:43:13 strconv.ParseInt: parsing "x6381": invalid syntax
Must*Удобный метод
Если вам нужно делать неверные выводы каждый раз, когда вы принимаете значение, тогда код будет очень громоздким для написания. к этому концу,go-iniтакже предоставить соответствующиеMustType(ТипInit/Uint/Float64etc), который возвращает только одно значение.
В то же время он принимает переменные параметры.Если тип не может быть преобразован, возвращается первое значение в параметре, и параметру присваивается значение этой конфигурации.Следующий вызов возвращает это значение:
package main
import (
"fmt"
"log"
"gopkg.in/ini.v1"
)
func main() {
cfg, err := ini.Load("my.ini")
if err != nil {
log.Fatal("Fail to read file: ", err)
}
redisPort, err := cfg.Section("redis").Key("port").Int()
if err != nil {
fmt.Println("before must, get redis port error:", err)
} else {
fmt.Println("before must, get redis port:", redisPort)
}
fmt.Println("redis Port:", cfg.Section("redis").Key("port").MustInt(6381))
redisPort, err = cfg.Section("redis").Key("port").Int()
if err != nil {
fmt.Println("after must, get redis port error:", err)
} else {
fmt.Println("after must, get redis port:", redisPort)
}
}
Файл конфигурации все еще находится в состоянии, когда порт redis не является числовым x6381, запустите программу:
before must, get redis port error: strconv.ParseInt: parsing "x6381": invalid syntax
redis Port: 6381
after must, get redis port: 6381
Мы видим первый звонокIntошибка возврата, вызов с 6381 в качестве аргументаMustIntПосле этого позвоните еще разInt, 6381 возвращается успешно.MustIntИсходный код относительно прост:
// gopkg.in/ini.v1/key.go
func (k *Key) MustInt(defaultVal ...int) int {
val, err := k.Int()
if len(defaultVal) > 0 && err != nil {
k.value = strconv.FormatInt(int64(defaultVal[0]), 10)
return defaultVal[0]
}
return val
}
операция разделения
получение информации
После загрузки конфигурации можно пройтиSectionsМетод Получить все разделы,SectionStrings()способ получить все имена разделов.
sections := cfg.Sections()
names := cfg.SectionStrings()
fmt.Println("sections: ", sections)
fmt.Println("names: ", names)
Прогон выводит 3 раздела:
[DEFAULT mysql redis]
перечислитьSection(name)получить имяnameЕсли раздел не существует, он автоматически создаст раздел и вернет:
newSection := cfg.Section("new")
fmt.Println("new section: ", newSection)
fmt.Println("names: ", cfg.SectionStrings())
Вызывается после созданияSectionStringsметод, новый раздел также возвращает:
names: [DEFAULT mysql redis new]
Также можно вручную создать новый раздел и вернуть ошибку, если раздел уже существует:
err := cfg.NewSection("new")
раздел родитель-потомок
В файле конфигурации можно использовать заполнители%(name)sУказывает на использование ранее определенного ключаnameзначение для замены, здесьsУказывает, что значение является строковым типом:
NAME = ini
VERSION = v1
IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s
[package]
CLONE_URL = https://%(IMPORT_PATH)s
[package.sub]
Выше находится в разделе по умолчаниюIMPORT_PATHзначение, определенное ранееNAMEиVERSION.
существуетpackageустановить в разделеCLONE_URLЗначение раздела по умолчанию используется, когдаIMPORT_PATH.
Мы также можем использовать в имени раздела.Представляет отношения родитель-потомок между двумя или более разделами, например.package.subРодительский разделpackage,packageРодительский раздел является разделом по умолчанию.
Если ключ не существует в дочернем разделе, он снова ищется в его родительском разделе до тех пор, пока не останется родительского раздела:
cfg, err := ini.Load("parent_child.ini")
if err != nil {
fmt.Println("Fail to read file: ", err)
return
}
fmt.Println("Clone url from package.sub:", cfg.Section("package.sub").Key("CLONE_URL").String())
Запуск вывода программы:
Clone url from package.sub: https://gopkg.in/ini.v1
Дочерние разделыpackage.subНет ключаCLONE_URL, который возвращает родительский разделpackageзначение в .
сохранить конфигурацию
Иногда нам нужно записать сгенерированную конфигурацию в файл. Например, при написании инструментов. Существует два типа интерфейсов для сохранения: один для сохранения непосредственно в файл, а другой для записи вio.Writerсередина:
err = cfg.SaveTo("my.ini")
err = cfg.SaveToIndent("my.ini", "\t")
cfg.WriteTo(writer)
cfg.WriteToIndent(writer, "\t")
Далее генерим использованный ранее конфигурационный файл через программуmy.iniи сохранить:
package main
import (
"fmt"
"os"
"gopkg.in/ini.v1"
)
func main() {
cfg := ini.Empty()
defaultSection := cfg.Section("")
defaultSection.NewKey("app_name", "awesome web")
defaultSection.NewKey("log_level", "DEBUG")
mysqlSection, err := cfg.NewSection("mysql")
if err != nil {
fmt.Println("new mysql section failed:", err)
return
}
mysqlSection.NewKey("ip", "127.0.0.1")
mysqlSection.NewKey("port", "3306")
mysqlSection.NewKey("user", "root")
mysqlSection.NewKey("password", "123456")
mysqlSection.NewKey("database", "awesome")
redisSection, err := cfg.NewSection("redis")
if err != nil {
fmt.Println("new redis section failed:", err)
return
}
redisSection.NewKey("ip", "127.0.0.1")
redisSection.NewKey("port", "6381")
err = cfg.SaveTo("my.ini")
if err != nil {
fmt.Println("SaveTo failed: ", err)
}
err = cfg.SaveToIndent("my-pretty.ini", "\t")
if err != nil {
fmt.Println("SaveToIndent failed: ", err)
}
cfg.WriteTo(os.Stdout)
fmt.Println()
cfg.WriteToIndent(os.Stdout, "\t")
}
Запустите программу, чтобы сгенерировать два файлаmy.iniиmy-pretty.ini, а консоль выводит содержимое файла.
my.ini:
app_name = awesome web
log_level = DEBUG
[mysql]
ip = 127.0.0.1
port = 3306
user = root
password = 123456
database = awesome
[redis]
ip = 127.0.0.1
port = 6381
my-pretty.ini:
app_name = awesome web
log_level = DEBUG
[mysql]
ip = 127.0.0.1
port = 3306
user = root
password = 123456
database = awesome
[redis]
ip = 127.0.0.1
port = 6381
*IndentМетод увеличит связь под поддоменом и выглядит красиво.
Отображение полей разделов и структур
Определите структурную переменную, после загрузки файла конфигурации вызовитеMapToПрисвойте элемент конфигурации соответствующему полю структурной переменной.
package main
import (
"fmt"
"gopkg.in/ini.v1"
)
type Config struct {
AppName string `ini:"app_name"`
LogLevel string `ini:"log_level"`
MySQL MySQLConfig `ini:"mysql"`
Redis RedisConfig `ini:"redis"`
}
type MySQLConfig struct {
IP string `ini:"ip"`
Port int `ini:"port"`
User string `ini:"user"`
Password string `ini:"password"`
Database string `ini:"database"`
}
type RedisConfig struct {
IP string `ini:"ip"`
Port int `ini:"port"`
}
func main() {
cfg, err := ini.Load("my.ini")
if err != nil {
fmt.Println("load my.ini failed: ", err)
}
c := Config{}
cfg.MapTo(&c)
fmt.Println(c)
}
MapToотражение используется внутри,Таким образом, все поля структуры должны быть экспортированы.. Если имя ключа не совпадает с именем поля, необходимо указать соответствующее имя ключа в теге структуры.
Это то же самое, что и стандартная библиотека Go.encoding/jsonиencoding/xmlразные. стандартная библиотекаjson/xmlПри разборе имя ключа может бытьapp_nameсоответствует имени поляAppName.
может быть, этоgo-iniТочки, где библиотека может быть оптимизирована?
Сначала загрузка, а затем сопоставление немного громоздко, используйте его напрямуюini.MapToОбъедините два шага:
err = ini.MapTo(&c, "my.ini")
Вы также можете отобразить только один раздел:
mysqlCfg := MySQLConfig{}
err = cfg.Section("mysql").MapTo(&mysqlCfg)
Конфигурации также могут быть сгенерированы из структур:
cfg := ini.Empty()
c := Config {
AppName: "awesome web",
LogLevel: "DEBUG",
MySQL: MySQLConfig {
IP: "127.0.0.1",
Port: 3306,
User: "root",
Password:"123456",
Database:"awesome",
},
Redis: RedisConfig {
IP: "127.0.0.1",
Port: 6381,
},
}
err := ini.ReflectFrom(cfg, &c)
if err != nil {
fmt.Println("ReflectFrom failed: ", err)
return
}
err = cfg.SaveTo("my-copy.ini")
if err != nil {
fmt.Println("SaveTo failed: ", err)
return
}
Суммировать
В этой статье описываетсяgo-iniОсновное использование библиотеки и некоторые интересные функции. Образец кода загруженGitHub.
фактическиgo-iniЕсть также много дополнительных функций.официальная документацияОчень подробно, рекомендуем к просмотру, и есть китайские йо~
авторнеизвестный, Я считаю, что те, кто занимается разработкой Go, не новички.
Ссылаться на
я
Добро пожаловать, чтобы обратить внимание на мою общедоступную учетную запись WeChat [GoUpUp], учитесь вместе и добивайтесь прогресса вместе ~
Эта статья опубликована в блогеOpenWriteвыпуск!