前言
最近工作和生活上比较忙,都没时间研究黑科技了(其实把玩游戏的时间挤出点来也就够了,不过不可能的),今天来水一篇,不对,更新一个常见配置文件格式对比以及使用方法。
常用的配置文件有这几种,最简单的Properties配置文件、经典的ini配置文件、依然保留一亩三分地的xml配置文件、在数据交换领域大显身手的json配置文件、以及充满野心的YAML配置文件等。
一个优秀的配置文件格式应该包含以下几个要素:
- 规则简单
- 可读性好
- 支持层级关系
- 允许注释
- 易于解析
- 逐行解析
- 支持列表和字典
- 支持多种数据类型
下面根据这几个要素分析一下它们的优劣和具体使用方法。
Properties
.properties 主要用在 JAVA 程序中,JAVA 内置对它的解析。它是一种简单的配置文件格式,规则大概只有下面几条:
- 使用
= :
或者空格作为键值对的分隔符; - 单引号和双引号会作为值的一部分;
- 允许使用
#
作为注释; - 可以使用
\
作为转义符,用来转义空格、换行和 Unicode 编码。
因为如此简单的格式,properteis 基本上不需要进行任何解释就能直接使用。也正因为它如此简单,不支持层级关系,因此它并不能算做好的配置文件 。
INI
INI相当于扩展版本的 properties ,包含 properties 的所有优点,去除了一些缺点,并且可以使用 section 来支持层级。它与 .properties 的主要区别如下:
- 支持 [section];
- 不使用空格作为分隔符;
- 允许在键名和值中直接包含空格(不需使用转义符);
- 支持更多的转义符。
综上,INI 格式是好的配置文件。
在Windows系统中,经常使用INI 文件作为系统或者第三方软件的配置文件,当然INI文件 的后缀名也不一定是”.ini”也可以是”.cfg”,”.conf ”或者是”.txt”。
格式
INI文件的格式很简单,最基本的三个要素是:parameters,sections 和 comments。
最基本的“元素”就是parameter也就是键值对,每一个parameter都有一个name和一个value,name和value由等号“=”隔开,name在等号的左边。
而所有的parameters都是以sections为单位结合在一起的。所有的section名称都是独占一行,并且sections名字都被方括号包围着。在section声明后的所有parameters都是属于该section。对于一个section没有明显的结束标志符,一个section的开始就是上一个section的结束。
comments也就是注释,是以分号“;”开始的。所有的注释语句不管多长都是独占一行直到结束的。在分号和行结束符之间的所有内容都是被忽略的。
读写示例
下面是一个简单的INI文件。
[mysql] ;这是IP host = localhost ;这是端口 port = 3307
使用Python读写INI文件的方式如下:
import configparser import os def readConf(): '''读取配置文件''' conf = configparser.ConfigParser() conf.read('test.conf') # 文件路径 properties = conf.items("mysql") print(properties) name = conf.get("mysql", "host") # 获取指定section 的option值 print(name) def writeConf(): '''写入配置文件''' conf = configparser.RawConfigParser() if not conf.has_section("mongodb"): conf.add_section("mongodb") if not conf.has_option("mongodb", "port"): conf.set("mongodb", "port","27777") with open("test.conf", "w") as confFile: conf.write(confFile)
JSON
由于 JavaScript 的流行,JSON 当然成了最适合 JavaScript 使用的配置文件。JSON 可以在 JavaScript 中使用 eval()
或者 JSON.parse()
来解析,解析后的内容直接成为 JavaScript 的内置对象。
但是,其实 JSON 不适合作为配置文件使用。根据上面的要素来看,JSON 规则简单但不易读(尤其是复杂的没有格式化过的 JSON),不支持注释,也不能使用较为宽松的语法,严格的格式规范下逐行解析就别想了。
JSON 的确是在网页和 API 中传递信息的一种好格式,而且各种语言都有它的解析库,很多开源工具也喜欢使用JSON做为配置文件,但显然并不是很适合做配置文件。
格式
JSON格式是基于列表和字典的,同样是通过键值对来记录数据,而值可以使子级的列表或者字典对象,从而可以实现复杂的嵌套关系。
读写实例
Python可以使用json库读写JSON格式,也可以使用pickle库进行处理。
区别是使用json库可以在不同语言之间交换数据的,而pickle库只在python之间使用。json库只能把常用的数据类型序列化(列表、字典、列表、字符串、数字),比如日期格式、类对象json就不行了。而pickle可以序列化所有的数据类型,包括类,函数都可以序列化。
首先是一个简单的JSON文件。
{ "name": "yumefx", "age": 3, "labels": [ { "labelName": "赌狗", "labelID": 1 }, { "labelName": "铳王", "labelID": 2 } ] }
下面以json库为例,对JSON文件进行读写。
import json import os def readJson(): '''读取配置文件''' with open("test.json", 'r') as load_f: load_dict = json.load(load_f) # 读取成Dict print(load_dict) def writeJson(): '''写入配置文件''' save_dict = {"name":""} with open("test.json", 'w') as save_f: json.dump(save_dict,save_f) # Dict写入 # Dict转str print(json.dumps({"name":["yumefx", "rick", "morty"]})) # str转Dict print(json.loads('{"name":["yumefx", "rick", "morty"]}'))
XML
XML是可扩展标记语言,格式类似HTML,虽然是好的配置文件格式 ,但它编辑起来太麻烦。即使是有 XML Notepad 这类软件的存在,太多的尖括号和嵌套也让手写这种配置文件变得艰难且更容易出错。
但很多软件的配置文件依然是基于XML的,因此依然有着一定的使用频率。
格式
XML的格式是基于XML元素的,元素包括起始标签、属性、内容以及结束标签,元素之间可以并列或者嵌套。
在HTML中,某些标签可以省略结束标签,而在XML中所有元素必须有结束标签;XML必须有根标签;XML的属性值必须使用引号包裹;标签不能以数字或标点符号开头,并且不能包含空格。
读写实例
一个简单的XML文件内容如下。
<?xml version='1.0' encoding='utf-8'?> <note> <!--你瞅啥--> <name language="ENU">yumefx</name> <status>sleeping</status> </note>
在Python中常见的XML编程接口有DOM和SAX,这两种接口处理XML文件的方式不同,使用场合也不同。python有三种方法解析XML:SAX,DOM和ElementTree。
其中SAX用的是事件驱动模型,通过在解析XML过程中触发一个个的事件并调用用户定义的回调函数来处理XML文件。这是一种流式处理,一边读一边解析,占用内存少。适合读取大文件或者只读取部分内容的场景。
DOM则是在解析一个XML文档时,一次性读取整个文档,把文档中所有元素保存在内存中的一个树结构里,之后利用DOM提供的不同函数来读取该文档的内容和结构,也可以把修改过的内容写入XML文件。考虑到性能,只适合读取一些简单的配置文件。
ElementTree则是一个轻量级的DOM,具有方便友好的API。代码可用性好,速度快,消耗内存少。
下面以ElementTree模式对XML文件进行读写。
from xml.etree import ElementTree as ET def readXML(): '''读取配置文件''' # 打开xml文档,读取内容为str str_xml = open('test.xml', 'r').read() # 将字符串解析成xml特殊对象,root代指xml文件的根节点 root = ET.XML(str_xml) # 或者直接解析XML文件成xml对象 # tree = ET.parse("test.xml") # root = tree.getroot() for child in root: print(child.tag, child.attrib) def writeXML(): '''写入配置文件''' root = ET.Element("famliy") son1 = ET.SubElement(root, "son", attrib={'name': 'child1'}) son2 = ET.SubElement(root, "son", attrib={"name": "child2"}) grandson1 = ET.SubElement(son1, "age", attrib={'name': 'grandChild11'}) grandson1.text = 'morty' et = ET.ElementTree(root) et.write("test.xml", encoding="utf-8", xml_declaration=True, short_empty_elements=False)
那么,有没有比较完美的配置文件格式呢?
有的,那就是XML的进化版YAML,篇幅所限,且听下回分解。
爱任何事物的方法,
就是要意识到你可能会失去它。
——G.K.切斯特顿
评论
658885 158843hi was just seeing in the event you minded a comment. i like your internet site and the thme you picked is awesome. I is going to be back. 218965
307512 350139Many thanks for sharing this fine piece. Very fascinating concepts! (as always, btw) 662880
425532 818337Hello! Someone in my Facebook group shared this website with us so I came to look it over. Im surely enjoying the info. Im book-marking and will likely be tweeting this to my followers! Outstanding weblog and superb style and design. 761981
609330 742282What others have stated and in some uncommon cases, suicide may occur. 451484
797845 785774Oh my goodness! a wonderful post dude. Thanks a lot Nevertheless I will be experiencing trouble with ur rss . Dont know why Not able to sign up for it. Is there everybody acquiring identical rss concern? Anybody who knows kindly respond. Thnkx 612945