gopkg.in/ini.v1 是 Go 中最常用稳定的第三方 INI 库,支持读写、结构体映射和注释保留,但写入为覆盖式;ini.Empty() 用于新建配置,ini.Load() 用于保留格式的修改;需避免重复 SaveTo 和节名拼写错误,并推荐原子写入保障安全。

用 gopkg.in/ini.v1 创建并写入 INI 文件
Go 官方不内置 INI 支持,gopkg.in/ini.v1 是最常用且稳定的第三方库。它支持读写、结构体映射、节(section)嵌套和注释保留,但写入是「覆盖式」的——每次调用 SaveTo 都会重写整个文件,无法追加或局部更新。
安装命令:
go get gopkg.in/ini.v1
基础写入示例:
package main
import (
"gopkg.in/ini.v1"
)
func main() {
cfg := ini.Empty()
cfg.NewSection("database")
cfg.Section("database").Key("host").SetValue("127.0.0.1")
cfg.Section("database").Key("port").SetValue("5432")
cfg.NewSection("cache")
cfg.Section("cache").Key("enabled").SetValue("true")
cfg.Section("cache").Key("ttl").SetValue("300")
cfg.SaveTo("config.ini")
}
ini.Empty() 与 ini.Load() 的关键区别
如果目标文件已存在,直接用 ini.Load("config.ini") 读取后修改再保存,能保留原有注释和空行;而 ini.Empty() 从零构建,生成的文件干净但无格式保留。
立即学习“go语言免费学习笔记(深入)”;
- 用
ini.Load():适合「读取现有配置 → 修改部分键 → 保存」场景 - 用
ini.Empty():适合「全新生成配置文件」,比如首次初始化或模板生成 - 若误用
ini.Load()加载不存在的文件,会返回错误,需显式检查:if err != nil && os.IsNotExist(err) { ... }
写入时控制格式与兼容性细节
gopkg.in/ini.v1 默认不写 BOM,生成 Unix 风格换行(\n),Windows 下打开可能显示为单行。如需强制 Windows 换行,得自己处理字节流;但更稳妥的做法是接受默认行为,因为 Go 程序自身跨平台读取完全不受影响。
常见格式控制点:
- 键名自动转小写(除非设置
ini.LoadOptions{Insensitive: false}) - 值中的空格不会被自动 trim,但双引号包裹的值(如
path = "/opt/data/")可安全含空格 - 注释只能通过
Comment方法添加到 section 或 key 上,不能单独写一行注释 - 写入前建议调用
cfg.Validate()检查是否有重复 section 名或非法字符
避免覆盖已有配置的典型误操作
新手常犯的错:在循环中反复调用 cfg.SaveTo(),导致每次只写入当前迭代内容,其余丢失。正确做法是先构造完整 cfg 对象,最后统一保存一次。
另一个易忽略点:cfg.Section("xxx").Key("y").SetValue("z") 中,如果 "xxx" 节不存在,Section() 会自动创建——这看似方便,但若拼写错误(比如 "databse"),就会悄悄新建错误节名,而不是报错。
建议防御性写法:
dbSec, err := cfg.GetSection("database")
if err != nil {
dbSec = cfg.NewSection("database")
}
dbSec.Key("host").SetValue("127.0.0.1")
INI 不是数据库,没有事务或原子写入机制。若程序在 SaveTo 过程中崩溃,可能留下损坏或截断的文件。生产环境应配合临时文件 + 原子重命名(os.Rename)来规避。










