常用配置文件格式简析

我大量使用过的配置文件主要有以下几种:

在这些中间,我最喜欢的三种格式是: lua、INI 和 YAML ,最不喜欢的是 JSON 。下面简单的说说它们。

优秀的配置文件

我认为 好的配置文件 必须包含下面几个因素:

1. 规则足够简单 2. 人类友好 在没有任何辅助工具的情况下清晰可读 3. 支持简单的层级关系 4. 允许注释

如果还包含下面几点,则可以认为是 优秀的配置文件

5. 易于解析(解析库有多种语言实现) 6. 逐行解析 在数据不完整的情况下不影响解析 7. 支持嵌套的层级关系 8. 支持列表和字典 9. 支持类型

lua 和 python

在 lua 开发中,由于 lua 语言的特性,使用一个 lua 文件作为配置文件是很常见也很自然的事情。在使用 quick-cocos2d-x 进行游戏开发的日子里,我大量使用 lua 的这种特性,甚至直接在配置文件中包含简单的逻辑来替换 _G 中的全局变量。而在使用这些配置文件的时候,只需要简单地 require 它们,lua 解释器会帮我们搞定一切。

当然,lua 作为配置文件的这种方便是 lua 解释器提供的,这也限制了 lua 配置文件的通用性。我们应该尽量在 lua 程序中使用 lua 作为配置文件。离开这个框架,则不太合适了。

python 的情况也类似。在 python 中,我将一个 dict 直接 dump 成为字符串,在使用这个配置文件的时候,使用 eval 解析。显然,这样使用并没有 lua 那样方便。

严格来说,这两种格式算不得配置文件。因为它们在特定的语言范畴易用,但缺乏跨语言和跨环境的通用性。例如,如果需要在 Python 中解析 lua 文件,可能需要自己写 解析器 来实现。

然而,我们可以使用语言的解析器来解析它们,可以不需要任何外部库可能直接使用它们,它们还完全符合我上面定义的 “好的配置文件” 标准。在没有其它选择(或不愿意进行选择),不考虑跨语言的前提下,它们用起来是挺不错的。

JSON —— 糟糕

由于 JavaScript 的流行,JSON 当然成了最适合 JavaScript 使用的配置文件。JSON 可以在 JavaScript 中使用 eval() 或者 JSON.parse() 来解析,解析后的内容直接成为 JavaScript 的内置对象。

但是,其实 JSON 不适合作为配置文件使用。根据上面我定义的 好的配置文件 条件来看:JSON 规则简单但不宜读(尤其是复杂的没有格式化过的 JSON),不支持注释,也不能使用较为宽松的语法。

例如,下面这种多余的逗号在 JSON 中被认为是错误的语法:

1JSON.parse('[1, 2, 3,]')
2// SyntaxError: JSON.parse: unexpected character at 
3// line 1 column 10 of the JSON data

JSON 的确是在网页和 API 中传递信息的一种好格式,而且各种语言都有它的解析库,但但并不适合做配置文件。

.properties 和 INI

.properties 主要用在 JAVA 程序中,JAVA 内置对它的解析。它是一种简单的配置文件格式,规则大概只有下面几条:

  1. 使用 = : 或者空格作为键值对的分隔符;
  2. 单引号和双引号会作为值的一部分;
  3. 允许使用 # 作为注释;
  4. 可以使用 \ 作为转义符,用来转义空格、换行和 Unicode 编码。

因为如此简单的格式,.properteis 基本上不需要进行任何解释就能直接使用。也正因为它如此简单,不支持层级关系,因此它并不能算做 好的配置文件

INI 则相当于扩展版本的 .properties ,包含 .properties 的所有优点,去除了一些缺点,并且可以使用 section 来支持层级。它与 .properties 的主要区别如下:

  1. 支持 [section];
  2. 不使用空格作为分隔符;
  3. 允许在键名和值中直接包含空格(不需使用转义符);
  4. 支持更多的转义符。

INI 格式是 好的配置文件 ,还包含 优秀的配置文件 的一些特性。由于解析简单,我们可以对它做一些扩展以符合我们的需求。

例如,我在 rookout 中对 ConfigParser 进行了一点点扩展,使得 ini 可以支持 [@list name] 这类特殊的 section ,将它们直接解析成 Python 中的 list。

XML 和 PLIST —— 虐心(也虐手)

XML 当然是 好的配置文件 ,但它编辑起来太麻烦。即使是有 XML Notepad 这类软件的存在,太多的尖括号和嵌套也让手写这种配置文件变得艰难。同样是由于太多的尖括号,让我不愿意阅读它。

PLIST 是 XML 的子集,是 Apple 定义的配置文件格式,在 Mac OS X 和 iOS 操作系统中得到大量的应用。PLIST 中直接包含类型信息,因此解析 PLIST 可以直接得到确定的数据类型(甚至是字典和数组)。 XCode 直接支持 PLIST 的编辑,但由于在 Apple 生态系统之外使用是在比较少,支持这种格式的编辑器和解析库都比较有限。当然你可以把它当作纯文本文件来编辑,那就又碰到了 XML 的问题。

我曾经用 ActionScript3 写过一个 PLIST 格式解析库,由于 AS3 对 XML 的原生支持,所以完成这个解析器还是很简单的工作。

同样,由于太多的尖括号,导致在版本管理中对不同的文件版本进行比较的时候并不太直观。

总之,我不愿意手写这两种配置文件格式,机器生成倒是很好的选择。

实际上,一些软件的特定文件格式就是基于 XML 的。例如 TexturePacker 的 tps 文件格式。

YAML —— 堪称完美

YAML: YAML Ain't Markup Language 是为了替代 XML 而生。它在 Ruby 中被发扬光大并为世人所知。下面摘抄一段关于 YAML 的评价,来自这里

为什么不是XML呢?因为:

  • YAML的可读性好。
  • YAML和脚本语言的交互性好。
  • YAML使用实现语言的数据类型。
  • YAML有一个一致的信息模型。
  • YAML易于实现。

上面5条也就是XML不足的地方。同时,YAML也有XML的下列优点:

  • YAML可以基于流来处理;
  • YAML表达能力强,扩展性好。

总之,YAML试图用一种比XML更敏捷的方式,来完成XML所完成的任务。

YAML 完全达到我上面提到的 优秀配置文件 的标准,到目前为止,堪称完美。

(全文完)