https://github.com/tinyhubs/properties
properties file reader & writer for go
https://github.com/tinyhubs/properties
java properties read write
Last synced: 23 days ago
JSON representation
properties file reader & writer for go
- Host: GitHub
- URL: https://github.com/tinyhubs/properties
- Owner: tinyhubs
- License: bsd-3-clause
- Created: 2017-04-09T13:32:19.000Z (almost 9 years ago)
- Default Branch: master
- Last Pushed: 2017-06-17T12:28:28.000Z (over 8 years ago)
- Last Synced: 2026-01-14T15:41:53.923Z (29 days ago)
- Topics: java, properties, read, write
- Language: Go
- Homepage:
- Size: 27.3 KB
- Stars: 8
- Watchers: 1
- Forks: 5
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Overview
[](https://travis-ci.org/tinyhubs/properties)
[](https://godoc.org/github.com/tinyhubs/properties)
[](https://github.com/tinyhubs/properties)
[](LICENSE)
[](https://codecov.io/gh/tinyhubs/properties)
[](https://www.goreportcard.com/report/github.com/tinyhubs/properties)
`*.properties`文件是java里面很常见的配置文件。这里是一个go语言版的*.properties文件读处理库。本库支持properties文件的读取、修改、回写操作。也支持向properties文件中的属性追加、删除注释操作。
## go-properties文件格式定义
为了使得properties文件的识别更加简单快速,go的properties的文件格式和java的properties文件并不是等价的。它将java里面一些很少用到的格式特性都去掉了。
golang版本的properties文件的格式定义如下:
- 一行如果第一个非空白字符是`#`或者`!`,那么整行将被识别为注释行,注释行将被解析器忽略。
比如,下面三行都会被解析器忽略(第三行是空白行):
```
# 这是注释行
! 这也是注释行
```
- 每个配置项都是单行的key-value对,**不支持跨行**,key和value以`=`或者`:`分隔。
比如,下面其实是三个配置项----`UserName=Fabirc \`、`Boch=`、`Contry=US`:
```
UserName = Fabirc \
Boch
Contry=US
```
- key和value都是区分大小写;
比如,下面其实是三个不同的配置项:
```
SizeRange=1-20
sizerange=1-20
SIZERANGE=1-20
```
- 一行的第一个`=`即使key与value的分隔字符,所以key中不会出现`=`,但value部分可以出现`=`;
比如,下面这个第一个行的key为`expr`,value是`A-B=C`;而第二行的key是一个`""`(空字符串),value是`Hello`。当然第二种情况并没有实际意义:
```
expr=A-B=C
=Hello
```
- key和value的前后的空白都将被忽略,但key和value中间的空白会被原样保留;
比如,下面这三个配置项的值都是`1-20`:
```
SizeRange-1=1-20
SizeRange-2 = 1-20
SizeRange-3 = 1-20
```
- properties文件只支持**`UTF-8`**字符集,所以value中可以直接输入中文,遇到中文字符不必像java那样使用`\uxxxx`转义,直接用中文字面文字即可;
比如,下面这个配置项的key为`地址`,value为`深圳`。
```
地址=深圳
```
- 当value为空时,等号可忽略;
所以,下面三个配置项的值都是空字符串(第一个等号后面有个):
```
Address-1=
Address-2=
Address-3
```
## 接口定义
#### 属性文档
一个properties文档由一个`properties.PropertiesDocument`对象来表示。一个properties文档由多个key-value形式的属性组成。每个属性还可以追加一行或者多行注释。
#### 加载属性文档
`properties.Load` 从io流生成一个`properties.PropertiesDocument`对象。
```go
file, err := os.Open("test1.properties")
if nil != err {
return
}
doc, err := properties.Load(file)
if nil != err {
t.Error("加载失败")
return
}
fmt.Println(doc.String("key"))
```
#### 创建一个新的属性文档对象
`properties.New` 直接创建一个新的属性文档对象,常用于属性创建文档文件的场景下。我们随后可以通过`properties.Save`函数将属性文档写入到文件或者输出流。
```go
doc := properties.New()
doc.Set("a", "aaa")
doc.Comment("a", "This is a comment for a")
buf := bytes.NewBufferString("")
properties.Save(doc, buf)
```
#### 将属性回写到文件或者流
`properties.Save` 可用于将一个文档回写到指定的writer中去。
```go
buf := bytes.NewBufferString("")
properties.Save(doc, buf)
```
#### 属性值的读取
- **通用读取能力**
PropertiesDocument对象的`Get`方法提供了一个基本的元素读取能力:
```go
func (p PropertiesDocument) Get(key string) (value string, exist bool)
```
`Get`函数会返回两个参数,当对应的key在PropertiesDocument文档中存在时,会返回该key对应的value,且exist的值将为true;如果不存在,exist的值将是false。
我们经常利用`Get`来探测,某个指定key的属性是否在属性文件中定义了。
- **读取并转换**
读取属性然后转成对应的数据类型是个很常见的任务,所以PropertiesDocument为最常用的几种类型提供了方便的读取并转换的函数。
* `String()` 读取一个字符串型的属性,如果不存在默认返回`""`
* `Int()` 读取一个属性并转换为`int64`类型,如果key对应的属性不存在,或者转换失败,返回值为0
* `Uint()` 和`Int()`函数类似,只是返回的数据类型为uint64
* `Float()` 也是和`Int()`函数类似,但返回值为float64
* `Bool()` 同与`String`类似,只是返回值是`bool`类型的且缺省值是`false`。`Bool`函数会将`1`, `t`, `T`, `true`, `TRUE`, `True`识别为`true`,将`0`, `f`, `F`, `false`, `FALSE`, `False`识别为`false`。
* `Object` 这个函数提供了一个数据映射能力,可以将找到的value映射为任何类型。
- **指定读取的缺省值**
前面的`String()`、`Int()`等函数在key不存在或者抓换失败的场景下,默认会返回零值。但零值往往不能满足我们的诉求,我们经常需要自己指定这些场景下的返回值。`StringDefault`,`IntDefault`、`FloatDefault`、`BoolDefault`、`ObjectDefault` 这几个函数的返回值和前面不带`Default`后缀的函数的行为类似,只是当配置项不存在时或者数据格式错误时,会直接返回参数中的`def`(缺省值)。
#### 属性的增删改
- **增加或者修改属性**
`Set()`函数用于修改指定的key的属性的值。如果指定的key的属性不存在,那么自动创建一个。
本库并没有提供按类型设置属性值的功能,前面描述的`Set()`函数只接受字符串类型的属性值作为输入。主要原因是数据的转换方式非常多,没有一种普适 的数据转换方法。所以,对于非字符串类型的值的设置需要自行转换成string类型。
```go
doc.Set("key", "value")
```
- **处理属性不存在的场景**
当属性不存在时,`Set()`函数会新建一个属性值,这种工作方式通常是很有用的。但是,有时候我们不希望`Set()`的这种自作聪明的行为。此时,我们可以通过`Get()`方法判断一些以确定是否需调用`Set()`。
```go
_, exist := doc.Get("key")
if !exist {
return errors.New("Key is not exist")
}
doc.Set("key", "New-Value")
```
- **删除属性**
`Del()`函数用于删除指定key的属性。它会返回一个bool值,用于表示当前的key的属性是否存在。
```go
exist := doc.Del("key")
```
#### 操作注释
在本库中,注释是绑定到属性的。位于属性的key-value定义前面,且与属性之间没有空白行的多行注释,我们会判定这些注释是属于该属性的,比如:
```properties
# Comment1
# Comment2
# Comment3
# Comment4
mykey=myvalue
```
上面的Comment3和Comment4是mykey属性的注释,但是Comment1和Comment2却不是。
PropertiesDocument的`Comment()`函数用于为属性指定一些注释。而`Uncomment()`函数用于删除指定的key的注释。
PropertiesDocument的`Comment()`函数允许一次性指定多行注释,而`Uncomment()`用于一次性删除一个指定的key的所有的注释。
#### 文档对象枚举
PropertiesDocument的`Accept()`和`Foreach()`函数都是用来对文档对象进行枚举的,但是`Foreach()`专用于对属性进行遍历。而`Accept()`可以通过对属性和注释进行遍历。
实际上,`Save()`函数就是利用`Accept()`函数来实现的:
```go
func Save(doc *PropertiesDocument, writer io.Writer) {
doc.Accept(func(typo byte, value string, key string) bool {
switch typo {
case '#', '!', ' ':
{
fmt.Fprintln(writer, value)
}
case '=', ':':
{
fmt.Fprintf(writer, "%s%c%s\n", key, typo, value)
}
}
return true
})
}
```
`Accept()`函数的回调函数里面有个`typo`参数,这个参数决定了当前这条记录是注释还是一个有效的属性。`typo`的取值可能有下面一些:
- `'#'` 表示当前的value是`#`开头的注释
- `'!'` 表示当前的value是`!`开头的注释
- `' '` 表示当前的value是个空行或者空白行
- `'='` 表示当前的value是个以`=`分隔的属性
- `':'` 表示当前的value是个以`:`分隔的属性