Go语言从INI配置文件中读取需要的值
来源:云海天教程
时间:2022-12-23 11:56:22 250浏览 收藏
IT行业相对于一般传统行业,发展更新速度更快,一旦停止了学习,很快就会被行业所淘汰。所以我们需要踏踏实实的不断学习,精进自己的技术,尤其是初学者。今天golang学习网给大家整理了《Go语言从INI配置文件中读取需要的值》,聊聊文件处理,我们一起来看看吧!
INI 文件格式是一种古老的配置文件格式。一些操作系统、虚幻游戏引擎、GIT 版本管理中都在使用 INI 文件格式。下面用从 GIT 版本管理的配置文件中截取的一部分内容,展示 INI 文件的样式。[core]
repositoryformatversion = 0
filemode = false
bare = false
logallrefupdates = true
symlinks = false
ignorecase = true
hideDotFiles = dotGitOnly
[remote "origin"]
url = https://github.com/davyxu/cellnet
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master
INI 文件的格式
INI 文件由多行文本组成,整个配置由“[]”拆分为多个“段”(section)。每个段中又以“=”分割为“键”,和“值”。INI 文件以“;”置于行首视为注释,本行将不会被处理和识别。INI 文件格式如下:
[sectionl]
key1=value1
key2=value2
[section2]
从 INI 文件中取值的函数
熟悉了 INI 文件的格式后,开始准备读取 INI 文件,并从文件中获取需要的数据。完整的示例代码如下所示:package mainimport ( "bufio" "fmt" "os" "strings")// 根据文件名,段名,键名获取ini的值func getValue(filename, expectSection, expectKey string) string { // 打开文件 file, err := os.Open(filename) // 文件找不到,返回空 if err != nil { return "" } // 在函数结束时,关闭文件 defer file.Close() // 使用读取器读取文件 reader := bufio.NewReader(file) // 当前读取的段的名字 var sectionName string for { // 读取文件的一行 linestr, err := reader.ReadString('') if err != nil { break } // 切掉行的左右两边的空白字符 linestr = strings.TrimSpace(linestr) // 忽略空行 if linestr == "" { continue } // 忽略注释 if linestr[0] == ';' { continue } // 行首和尾巴分别是方括号的,说明是段标记的起止符 if linestr[0] == '[' && linestr[len(linestr)-1] == ']' { // 将段名取出 sectionName = linestr[1 : len(linestr)-1] // 这个段是希望读取的 } else if sectionName == expectSection { // 切开等号分割的键值对 pair := strings.Split(linestr, "=") // 保证切开只有1个等号分割的简直情况 if len(pair) == 2 { // 去掉键的多余空白字符 key := strings.TrimSpace(pair[0]) // 是期望的键 if key == expectKey { // 返回去掉空白字符的值 return strings.TrimSpace(pair[1]) } } } } return ""}func main() { fmt.Println(getValue("example.ini", "remote "origin"", "fetch")) fmt.Println(getValue("example.ini", "core", "hideDotFiles"))}本例并不是将整个 INI 文件读取保存后再获取需要的字段数据并返回,这里使用 getValue() 函数,每次从指定文件中找到需要的段(Section)及键(Key)对应的值。
getValue() 函数的声明如下:
func getValue(filename, expectSection, expectKey string) string
参数说明如下。filename:INI 文件的文件名。expectSection:期望读取的段。expectKey:期望读取段中的键。
getValue() 函数的实际使用例子参考代码如下:
func main() {
fmt.Println(getValue("example.ini", "remote "origin"", "fetch"))
fmt.Println(getValue("example.ini", "core", "hideDotFiles"))
}
+refs/heads/*:refs/remotes/origin/*
dotGitOnly
注意代码第 2 行中,由于段名中包含双引号,所以使用“\”进行转义。
getValue() 函数的逻辑由 4 部分组成:即读取文件、读取行文本、读取段和读取键值组成。接下来分步骤了解 getValue() 函数的详细处理过程。
读取文件
Go语言的 OS 包中提供了文件打开函数 os.Open()。文件读取完成后需要及时关闭,否则文件会发生占用,系统无法释放缓冲资源。参考下面代码:// 打开文件file, err := os.Open(filename)// 文件找不到,返回空if err != nil { return ""}// 在函数结束时,关闭文件defer file.Close()代码说明如下:第 2 行,filename 是由 getValue() 函数参数提供的 INI 的文件名。使用 os.Open() 函数打开文件,如果成功打开,会返回文件句柄,同时返回打开文件时可能发生的错误:err。第 5 行,如果文件打开错误,err 将不为 nil,此时 getValue() 函数返回一个空的字符串,表示无法从给定的 INI 文件中获取到需要的值。第 10 行,使用 defer 延迟执行函数,defer 并不会在这一行执行,而是延迟在任何一个 getValue() 函数的返回点,也就是函数退出的地方执行。调用 file.Close() 函数后,打开的文件就会被关闭并释放系统资源。
INI 文件已经打开了,接下来就可以开始读取 INI 的数据了。
读取行文本
INI 文件的格式是由多行文本组成,因此需要构造一个循环,不断地读取 INI 文件的所有行。Go语言总是将文件以二进制格式打开,通过不同的读取方式对二进制文件进行操作。Go语言对二进制读取有专门的代码抽象,bufio 包即可以方便地以比较常见的方式读取二进制文件。// 使用读取器读取文件reader := bufio.NewReader(file)// 当前读取的段的名字var sectionName stringfor { // 读取文件的一行 linestr, err := reader.ReadString('') if err != nil { break } // 切掉行的左右两边的空白字符 linestr = strings.TrimSpace(linestr) // 忽略空行 if linestr == "" { continue } // 忽略注释 if linestr[0] == ';' { continue } //读取段和键值的代码 //...}代码说明如下:
第 2 行,使用 bufio 包提供的 NewReader() 函数,传入文件并构造一个读取器。第 5 行,提前声明段的名字字符串,方便后面的段和键值读取。第 7 行,构建一个读取循环,不断地读取文件中的每一行。第 10 行,使用 reader.ReadString() 从文件中读取字符串,直到碰到“”,也就是行结束。这个函数返回读取到的行字符串(包括“”)和可能的读取错误 err,例如文件读取完毕。第 16 行,每一行的文本可能会在标识符两边混杂有空格、回车符、换行符等不可见的空白字符,使用 strings.TrimSpace() 可以去掉这些空白字符。第 19 行,可能存在空行的情况,继续读取下一行,忽略空行。第 24 行,当行首的字符为“;”分号时,表示这一行是注释行,忽略一整行的读取。
读取 INI 文本文件时,需要注意各种异常情况。文本中的空白符就是经常容易忽略的部分,空白符在调试时完全不可见,需要打印出字符的 ASCII 码才能辨别。
抛开各种异常情况拿到了每行的行文本 linestr 后,就可以方便地读取 INI 文件的段和键值了。
读取段
行字符串 linestr 已经去除了空白字符串,段的起止符又以“[”开头, 以“]”结尾,因此可以直接判断行首和行尾的字符串匹配段的起止符匹配时读取的是段,如下图所示。图:INI 文件的段名解析
此时,段只是一个标识,而无任何内容,因此需要将段的名字取出保存在 sectionName(己在之前的代码中定义)中,待读取段后面的键值对时使用。
// 行首和尾巴分别是方括号的,说明是段标记的起止符if linestr[0] == '[' && linestr[len(linestr)-1] == ']' { // 将段名取出 sectionName = linestr[1 : len(linestr)-1] // 这个段是希望读取的}代码说明如下:
第 2 行,linestr[0] 表示行首的字符,len(linestr)-1 取出字符串的最后一个字符索引随后取出行尾的字符。根据两个字符串是否匹配方括号,断定当前行是否为段。第 5 行,linestr 两边的“[”和“]”去掉,取出中间的段名保存在 sectionName 中,留着后面的代码用。
读取键值
这里代码紧接着前面的代码。当前行不是段时(不以“[”开头),那么行内容一定是键值对。别忘记此时 getValue() 的参数对段有匹配要求。找到能匹配段的键值对后,开始对键值对进行解析,参考下面的代码:else if sectionName == expectSection { // 切开等号分割的键值对 pair := strings.Split(linestr, "=") // 保证切开只有1个等号分割的简直情况 if len(pair) == 2 { // 去掉键的多余空白字符 key := strings.TrimSpace(pair[0]) // 是期望的键 if key == expectKey { // 返回去掉空白字符的值 return strings.TrimSpace(pair[1]) } }}代码说明如下:
第 1 行,当前的段匹配期望的段时,进行后面的解析。第 4 行,对行内容(linestr)通过 strings.Split() 函数进行切割,INI 的键值对使用“=”分割,分割后,strings.Split() 函数会返回字符串切片,类型为 []string。这里只考虑一个“=”的情况,因此被分割后,strings.Split() 函数返回的字符串切片有 2 个元素。第 7 行,只考虑切割出 2 个元素的情况。其他情况会被忽略, 键值如没有“=”、行中多余一个“=”等情况。第 10 行,pair[O] 表示“=”左边的键。使用 strings.TrimSpace() 函数去掉空白符,如下图所示。第 13 行,键值对切割出后,还需要判断键是否为期望的键。第 16 行,匹配期望的键时,将 pair[1] 中保存的键对应的值经过去掉空白字符处理后作为函数返回值返回。
图:lNI 的键值解析
今天带大家了解了文件处理的相关知识,希望对你有所帮助;关于Golang的技术知识我们会一点点深入介绍,欢迎大家关注golang学习网公众号,一起学习编程~
-
225 收藏
-
389 收藏
-
250 收藏
-
137 收藏
-
190 收藏
-
113 收藏
-
140 收藏
-
277 收藏
-
186 收藏
-
346 收藏
-
286 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 507次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习
-
- 壮观的云朵
- 受益颇多,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢楼主分享文章内容!
- 2023-02-15 13:54:30
-
- 发嗲的火车
- 这篇文章内容太及时了,作者大大加油!
- 2023-02-11 05:49:47
-
- 痴情的雪碧
- 真优秀,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,帮助很大,总算是懂了,感谢博主分享技术文章!
- 2023-02-08 18:29:33
-
- 光亮的小蝴蝶
- 这篇技术文章出现的刚刚好,很详细,写的不错,已加入收藏夹了,关注up主了!希望up主能多写Golang相关的文章。
- 2023-02-01 10:05:31
-
- 无限的老虎
- 这篇文章太及时了,太全面了,受益颇多,收藏了,关注大佬了!希望大佬能多写Golang相关的文章。
- 2023-01-28 14:09:43
-
- 斯文的帆布鞋
- 太全面了,码起来,感谢大佬的这篇博文,我会继续支持!
- 2023-01-23 00:00:02
-
- 烂漫的黑夜
- 这篇博文出现的刚刚好,细节满满,感谢大佬分享,码住,关注作者大大了!希望作者大大能多写Golang相关的文章。
- 2023-01-22 15:56:21
-
- 老实的吐司
- 很棒,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢作者大大分享技术贴!
- 2023-01-19 05:32:43
-
- 热心的仙人掌
- 细节满满,mark,感谢老哥的这篇文章内容,我会继续支持!
- 2023-01-17 15:29:10
-
- 执着的百褶裙
- 太细致了,mark,感谢作者的这篇技术文章,我会继续支持!
- 2023-01-12 20:55:14
-
- 简单的香氛
- 这篇文章真是及时雨啊,太全面了,太给力了,收藏了,关注师傅了!希望师傅能多写Golang相关的文章。
- 2023-01-10 05:54:36
-
- 虚心的小丸子
- 细节满满,已收藏,感谢老哥的这篇博文,我会继续支持!
- 2023-01-09 01:51:30
-
- 干净的悟空
- 这篇技术贴太及时了,师傅加油!
- 2023-01-01 14:54:42
-
- 壮观的云朵
- 很好,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,帮助很大,总算是懂了,感谢师傅分享文章内容!
- 2022-12-31 04:52:18
-
- 阳光的小海豚
- 这篇技术文章太及时了,太细致了,太给力了,码住,关注大佬了!希望大佬能多写Golang相关的文章。
- 2022-12-28 15:53:33
-
- 聪慧的小丸子
- 这篇文章内容出现的刚刚好,很详细,很好,已加入收藏夹了,关注楼主了!希望楼主能多写Golang相关的文章。
- 2022-12-25 12:41:10