BLOG

Record, summarize, and improve.

常用配置文件格式

配置文件是工程中常用的初始化参数的配置方式,而配置文件的格式有很多种,不同的操作系统、编程语言都会有不同的配置文件的格式,本文罗列了一些常见的配置文件的格式。

不同的配置文件格式有不同的用户友好性, 对于功能的支持也有简单和复杂之分,很难简单说那种配置文件是最好的,有时候需要从多个方面去考虑, 比如Windows较早的开发喜欢使用ini、java喜欢使用properties、通用的编程喜欢yamljson等格式,本文也不会对这些格式进行排名,而是简单介绍一下这些格式,用户可以根据自己的实际情况进行选择。

ini

ini文件是一个无固定标准格式的配置文件。它以简单的文字与简单的结构组成,常常使用在Windows操作系统。ini文件的命名来源,是取自英文“初始(Initial)”的首字缩写,正与它的用途——初始化程序相应。

文件格式比较简单, 分为 参数注释。下面是一个简单的ini配置文件:

https://github.com/Microsoft/Windows-driver-samples/blob/master/print/v4PrintDriverSamples/v4PrintDriver-HostBasedSampleDriver/usb_host_based_sample-manifest.ini

[DriverConfig]
DriverCategory=PrintFax.Printer
DataFile=usb_host_based_sample.gpd

; Note: Please replace the GUID below when building a production driver.
PrinterDriverID={00000000-0000-0000-0000-000000000000}
Flags=HostBasedDevice
EventFile=usb_host_based_sample_events.xml
RequiredFiles=UNIRES.DLL,STDNAMES.GPD,MSXPSINC.GPD

[BidiFiles]
BidiUSBFile=usb_host_based_sample_extension.xml
BidiUSBJSFile=usb_host_based_sample.js

properties

properties是一种主要在Java相关技术中用来存储应用程序的可配置参数的文件的文件扩展名。它们也可以存储用于国际化和本地化的字符串,这种文件被称为属性资源包(Property Resource Bundles)。每个参数被存储为一对字符串:一个存储名称参数(被称为“键”),另一个存储值。

每个properties 文件中的行通常存储单个属性。对于每一行可能有这么几种格式,包括键=值,键 = 值,键:值,以及键 值。.properties文件可以使用井号(#)或叹号(!)作为一行中第一个非空白字符来表示它后面的所有文本都是一个注释。反斜杠(\)用于转义字符。下面是一个properties文件:

https://github.com/netgloo/spring-boot-samples/blob/master/spring-boot-mysql-springdatajpa-hibernate/src/main/resources/application.properties

# ===============================
# = DATA SOURCE
# ===============================

# Set here configurations for the database connection

# Connection url for the database "netgloo_blog"
spring.datasource.url = jdbc:mysql://localhost:3306/netgloo_blog?useSSL=false

# Username and password
spring.datasource.username = root
spring.datasource.password = root

# Keep the connection alive if idle for a long time (needed in production)
spring.datasource.testWhileIdle = true
spring.datasource.validationQuery = SELECT 1

# ===============================
# = JPA / HIBERNATE
# ===============================

# Use spring.jpa.properties.* for Hibernate native properties (the prefix is
# stripped before adding them to the entity manager).

# Show or not log for each sql query
spring.jpa.show-sql = true

# Hibernate ddl auto (create, create-drop, update): with "update" the database
# schema will be automatically updated accordingly to java entities found in
# the project
spring.jpa.hibernate.ddl-auto = update

# Naming strategy
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy

# Allows Hibernate to generate SQL optimized for a particular DBMS
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect

json

JSON(JavaScript Object Notation)是一种轻量级的数据交换语言,以文字为基础,且易于让人阅读。尽管JSON是Javascript的一个子集,但JSON是独立于语言的文本格式,并且采用了类似于C语言家族的一些习惯。JSON 数据格式与语言无关,脱胎于 JavaScript,但目前很多编程语言都支持 JSON 格式数据的生成和解析, 所以也常常用作配置文件。

JSON用于描述数据结构,有以下形式存在。

  • 对象(object):一个对象以{开始,并以}结束。一个对象包含一系列非排序的名称/值对,每个名称/值对之间使用,分区
  • 名称/值(collection):名称和值之间使用隔开,一般的形式是:{name:value}
  • 值的有序列表(Array):一个或者多个值用,分区后,使用[,]括起来就形成了这样的列表
  • 字符串:以""括起来的一串字符。
  • 数值:一系列0-9的数字组合,可以为负数或者小数。还可以用e或者E表示为指数形式。
  • 布尔值:表示为true或者false。

JSON的格式描述可以参考RFC 4627。

下面是一个json配置文件的例子:

https://github.com/hashicorp/vault/blob/master/command/server/test-fixtures/config.hcl.json

{
	"listener": [{
		"tcp": {
			"address": "127.0.0.1:443"
		}
	}],
	"cluster_cipher_suites": "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
	"storage": {
		"consul": {
			"foo": "bar",
			"disable_clustering": "true"
		}
	},
	"service_registration": {
		"consul": {
			"foo": "bar"
		}
	},
	"telemetry": {
		"statsite_address": "baz",
		"usage_gauge_period": "5m",
		"maximum_gauge_cardinality": 100
	},
	"sentinel": {
		"additional_enabled_modules": []
	},
	"max_lease_ttl": "10h",
	"default_lease_ttl": "10h",
	"cluster_name":"testcluster",
	"ui":true,
	"pid_file":"./pidfile",
	"raw_storage_endpoint":true,
	"disable_sealwrap":true
}

xml

xml是一种标记语言。标记指计算机所能理解的信息符号,通过此种标记,计算机之间可以处理包含各种信息的文章等。XML是从1995年开始有其雏形,并向W3C(万维网联盟)提案,而在1998年二月发布为W3C的标准(XML1.0)。

XML设计用来传送及携带数据信息,所以也经常用来做配置文件。

xml实例:

https://github.com/kpavlov/spring-cloud-config-sample/blob/master/src/main/resources/spring-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">

    <context:property-placeholder location="
    ${config.uri}/company.properties,
    classpath:product.properties,
    ${config.uri}/${product.name}/${product.version}/common.properties,
    ${config.uri}/${product.name}/${product.version}/${config.stage}/stage.properties,
    ${config.uri}/${product.name}/${product.version}/${config.stage}/${config.node}/node.properties"
                                  system-properties-mode="FALLBACK"/>

    <context:annotation-config/>

    <context:component-scan base-package="spring"/>

</beans>

yaml

YAML(/ˈjæməl/,尾音类似camel骆驼)是一个可读性高,用来表达数据序列的格式。Clark Evans在2001年首次发表了这种语言,另外Ingy döt Net与Oren Ben-Kiki也是这语言的共同设计者。目前已经有数种编程语言或脚本语言支持(或者说解析)这种语言。

YAML是"YAML Ain't a Markup Language"(YAML不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:"Yet Another Markup Language"(仍是一种标记语言,但为了强调这种语言以数据做为中心,而不是以标记语言为重点,而用反向缩略语重命名。

YAML的语法和其他高级语言类似,并且可以简单表达清单、散列表,标量等数据形态。它使用空白符号缩进和大量依赖外观的特色, 比较适合用来表达层次结构式的数据结构。

YAML 1.2 是 JSON 格式的超集

https://github.com/prometheus/prometheus/blob/master/config/testdata/conf.good.yml

# my global config
global:
  scrape_interval: 15s
  evaluation_interval: 30s
  # scrape_timeout is set to the global default (10s).

  external_labels:
    monitor: codelab
    foo: bar

rule_files:
  - "first.rules"
  - "my/*.rules"

remote_write:
  - url: http://remote1/push
    name: drop_expensive
    write_relabel_configs:
      - source_labels: [__name__]
        regex: expensive.*
        action: drop
    oauth2:
      client_id: "123"
      client_secret: "456"
      token_url: "http://remote1/auth"
      tls_config:
        cert_file: valid_cert_file
        key_file: valid_key_file

  - url: http://remote2/push
    name: rw_tls
    tls_config:
      cert_file: valid_cert_file
      key_file: valid_key_file
    headers:
      name: value

toml https://zh.wikipedia.org/wiki/TOML

TOML是一种旨在成为一个小规模、易于使用的语义化的配置文件格式,它被设计为可以无二义性的转换为一个哈希表。“TOML”这个名字是“Tom's Obvious, Minimal Language(汤姆的浅显的、极简的语言)”的首字母略写词。“Tom”指它的作者Tom Preston-Werner。TOML已在一些软件工程中使用,并且可在很多程序语言中执行。

TOML的语法广泛地由key = "value"[节名]#注释构成。它支持以下数据类型:字符串、整形、浮点型、布尔型、日期时间、数组和图表。

# 這是一份 TOML 文件

title = "TOML 範例"

[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00 # First class dates

[database]
server = "192.168.1.1"
ports = [ 8001, 8001, 8002 ]
connection_max = 5000
enabled = true

[servers]

  # 可以使用縮排(TAB或是空格),但不是必要的
  [servers.alpha]
  ip = "10.0.0.1"
  dc = "eqdc10"

  [servers.beta]
  ip = "10.0.0.2"
  dc = "eqdc10"

[clients]
data = [ ["gamma", "delta"], [1, 2] ]

# 可以在陣列中換行
hosts = [
  "alpha",
  "omega"
]

HOCON

HOCON,全称Human-Optimized Config Object Notation(人性化配置对象表示法)是一种人类可读的数据格式,并是JSON和properties的一个超集。它由Lightbend(用Scala开发的人都知道)开发,主要与Play框架结合使用。它也在Puppet中作为配置格式使用。

基本上也算是Scala官方开发,所以在Scala的一些项目中得到使用。由于它是JSON和properties格式的超集,所以它的格式比较灵活。

格式定义可以参考官方文档: HOCON

下面是它的一个实例:

https://github.com/marcospereira/play-i18n-hocon/blob/master/samples/scala/conf/application.conf

play.http.secret.key = "changeme"

play.modules {
  # Disable built-in i18n module
  disabled += play.api.i18n.I18nModule

  # Enable Hocon module
  enabled += com.marcospereira.play.i18n.HoconI18nModule
}

play.i18n {
  langs = [ "en" ]
}

plist

在OS X的Cocoa,NeXTSTEP和GNUstep编程框架中,属性列表(Property List)文件是一种用来存储序列化后的对象的文件。属性列表文件的文件扩展名为.plist,因此通常被称为plist文件。Plist文件通常用于储存用户设置,也可以用于存储捆绑的信息,该功能在旧式的Mac OS中是由资源分支提供的。

https://github.com/wahlmanj/com.plex.pms.plist/blob/master/com.plex.pms.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" 
    "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.plex.pms</string>
<key>KeepAlive</key>
<true/>
<key>ProgramArguments</key>
<array>
<string>/Applications/Plex Media Server.app/Contents/MacOS/Plex Media Server</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>UserName</key>
<string>__USERNAME__</string>
<key>WorkingDirectory</key>
<string>/Applications</string>
<key>ServiceDescription</key>
<string>PMS</string>
</dict>
</plist>

YAML语法

  • 大小写敏感
  • 使用缩进表示层级关系
  • 缩进时不允许使用Tab键,只允许使用空格。
  • 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可

# 表示注释,从这个字符一直到行尾,都会被解析器忽略。

YAML 支持的数据结构有三种。

  • 对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
  • 数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
  • 纯量(scalars):单个的、不可再分的值

对象

对象的一组键值对,使用冒号结构表示。

animal: pets

转为 JavaScript 如下。

{ animal: 'pets' }

Yaml 也允许另一种写法,将所有键值对写成一个行内对象。

hash: { name: Steve, foo: bar }

转为 JavaScript 如下。

{ hash: { name: 'Steve', foo: 'bar' } }

数组

一组连词线开头的行,构成一个数组。

- Cat
- Dog
- Goldfish

转为 JavaScript 如下。

[ 'Cat', 'Dog', 'Goldfish' ]

数据结构的子成员是一个数组,则可以在该项下面缩进一个空格。

-
 - Cat
 - Dog
 - Goldfish

转为 JavaScript 如下。

[ [ 'Cat', 'Dog', 'Goldfish' ] ]

数组也可以采用行内表示法。

animal: [Cat, Dog]

转为 JavaScript 如下。

{ animal: [ 'Cat', 'Dog' ] }

复合结构

对象和数组可以结合使用,形成复合结构。

languages:
 - Ruby
 - Perl
 - Python 
websites:
 YAML: yaml.org 
 Ruby: ruby-lang.org 
 Python: python.org 
 Perl: use.perl.org

转为 JavaScript 如下。

{ languages: [ 'Ruby', 'Perl', 'Python' ],
  websites: 
   { YAML: 'yaml.org',
     Ruby: 'ruby-lang.org',
     Python: 'python.org',
     Perl: 'use.perl.org' } }

纯量

纯量是最基本的、不可再分的值。以下数据类型都属于 JavaScript 的纯量

  • 字符串
  • 布尔值
  • 整数
  • 浮点数
  • Null
  • 时间
  • 日期

数值直接以字面量的形式表示。

number: 12.30

转为 JavaScript 如下。

{ number: 12.30 }

布尔值用truefalse表示。

isSet: true

转为 JavaScript 如下。

{ isSet: true }

null~表示。

parent: ~

转为 JavaScript 如下。

{ parent: null }

时间采用 ISO8601 格式。

iso8601: 2001-12-14t21:59:43.10-05:00

转为 JavaScript 如下。

{ iso8601: new Date('2001-12-14t21:59:43.10-05:00') }

日期采用复合 iso8601 格式的年、月、日表示

date: 1976-07-31

转为 JavaScript 如下。

{ date: new Date('1976-07-31') }

YAML 允许使用两个感叹号,强制转换数据类型。

e: !!str 123
f: !!str true

转为 JavaScript 如下。

{ e: '123', f: 'true' }

字符串

字符串默认不使用引号表示。

str: 这是一行字符串

转为 JavaScript 如下。

{ str: '这是一行字符串' }

如果字符串之中包含空格或特殊字符,需要放在引号之中。

str: '内容: 字符串'

转为 JavaScript 如下。

{ str: '内容: 字符串' }

单引号和双引号都可以使用,双引号不会对特殊字符转义。

s1: '内容\n字符串'
s2: "内容\n字符串"

转为 JavaScript 如下。

{ s1: '内容\\n字符串', s2: '内容\n字符串' }

单引号之中如果还有单引号,必须连续使用两个单引号转义。

str: 'labor''s day'

转为 JavaScript 如下。

{ str: 'labor\'s day' }

字符串可以写成多行,从第二行开始,必须有一个单空格缩进。换行符会被转为空格。

str: 这是一段
  多行
  字符串

转为 JavaScript 如下。

{ str: '这是一段 多行 字符串' }

多行字符串可以使用|保留换行符,也可以使用>折叠换行。

this: |
  Foo
  Bar
that: >
  Foo
  Bar

转为 JavaScript 代码如下。

{ this: 'Foo\nBar\n', that: 'Foo Bar\n' }

+表示保留文字块末尾的换行,-表示删除字符串末尾的换行。

s1: |
  Foo

s2: |+
  Foo


s3: |-
  Foo

转为 JavaScript 代码如下。

{ s1: 'Foo\n', s2: 'Foo\n\n\n', s3: 'Foo' }

字符串之中可以插入 HTML 标记。

message: |

  <p style="color: red">
    段落
  </p>

转为 JavaScript 如下。

{ message: '\n<p style="color: red">\n 段落\n</p>\n' }

引用

锚点&和别名*,可以用来引用。

defaults: &defaults
  adapter:  postgres
  host:     localhost

development:
  database: myapp_development
  <<: *defaults

test:
  database: myapp_test
  <<: *defaults

等同于下面的代码。

defaults:
  adapter:  postgres
  host:     localhost

development:
  database: myapp_development
  adapter:  postgres
  host:     localhost

test:
  database: myapp_test
  adapter:  postgres
  host:     localhost

&用来建立锚点(defaults),<<表示合并到当前数据,*用来引用锚点。

下面是另一个例子。

- &showell Steve 
- Clark 
- Brian 
- Oren 
- *showell

转为 JavaScript 代码如下。

[ 'Steve', 'Clark', 'Brian', 'Oren', 'Steve' ]

函数和正则表达式的转换

这是 JS-YAML 库特有的功能,可以把函数和正则表达式转为字符串。

# example.yml
fn: function () { return 1 }
reg: /test/

解析上面的 yml 文件的代码如下。

var yaml = require('js-yaml');
var fs   = require('fs');

try {
  var doc = yaml.load(
    fs.readFileSync('./example.yml', 'utf8')
  );
  console.log(doc);
} catch (e) {
  console.log(e);
}

从 JavaScript 对象还原到 yaml 文件的代码如下。

var yaml = require('js-yaml');
var fs   = require('fs');

try {
  var doc = yaml.load(
    fs.readFileSync('./example.yml', 'utf8')
  );
  console.log(doc);
} catch (e) {
  console.log(e);
}