Go ежедневная библиотека go-ini

Go

Введение

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, не новички.

Ссылаться на

  1. go-iniРепозиторий GitHub
  2. go-iniофициальная документация

я

мой блог

Добро пожаловать, чтобы обратить внимание на мою общедоступную учетную запись WeChat [GoUpUp], учитесь вместе и добивайтесь прогресса вместе ~

Эта статья опубликована в блогеOpenWriteвыпуск!