一、ini配置文件介绍
为什么要用INI文件?如果我们的程序没有任何配置文件时,这样的程序对外是全封闭的,一旦程序需要修改一些参数必须要修改程序代码本身并重新编译,这样很不好,所以要用配置文件,让程序出厂后还能根据需要进行必要的配置;配置文件有很多,如INI配置文件,XML配置文件,还有就是可以使用系统注册表等。
1.1 简介
*.ini文件是Initialization file的缩写,即为初始化文件,是Windows系统配置文件所采用的存储格式,统管Windows的各项配置,一般用户就用Windows提供的各项图形化管理界面就可以实现相同的配置了。但在某些情况,还是要直接编辑ini才方便,一般只有很熟悉Windows才能去直接编辑。
*.ini开始时使用于WIN3X下面,WIN95用注册表代替。
除了windows2003很多其他操作系统下面的应用软件也有*.ini文件,用来配置应用软件以实现不同用户的要求。一般不用直接编辑这些ini文件,应用程序的图形界面即可操作以实现相同的功能。它可以用来存放软件信息、注册表信息等。
1.2 文件扩展名
配置文件.ini
请注意:我们所讨论的是项目中的配置文件,它是整个项目共用的,所以它要有一个项目使用的文件名,其后缀是.ini。例如:端口配置 port.ini。
1.3 格式
ini配置文件由节、键、值组成。
【节】:
[section]
【参数】(键=值):
name=value
【注解】:
注解使用分号表示(;),在分号后面的文字,直到该行结尾都全部为注释。
;comment textINI文件的数据格式的例子(配置文件的内容)
【举例】:
[Section1 Name]
Keyname1=value1
Keyname2=value2
... ...
[Section2 Name]
Keyname21=value21
Keyname22=value22
[Section1 Name]用来表示一个段落,因为INI文件可能是项目中共用的,所以使用Section Name段名来区分不同用途的参数区。例如[Section1 Name]表示传感器灵敏度参数区;[Section2 Name]表示测量通道参数区等等。
Keyname1=value1用来表示一个参数名和值。比如:Num=80,Name=app。
1.4 实例
如下为串口的一个INI配置实例:
; exp ini file
[port]
Portname=COM4
Port=4
1.5 作用
*.ini、*.inc之类的文件,一般是放一些常量或数据库链接语句等,再在需要的页面包含进去,和直接命为adp是没什么区别的。
但为了安全性,最好不要用这些后缀名,因为知道文件名时,在浏览器里输入该文件的地址时,可看到所有内容的。
在Windows系统中,INI文件是很多,最重要的就是“System.ini”、“System32.ini”和“Win.ini”。该文件主要存放用户所做的选择以及系统的各种参数。用户可以通过修改INI文件,来改变应用程序和系统的很多配置。但自从Window 95的推出,在Windows系统中引入了注册表的概念,INI文件在Windows系统的地位就开始不断下滑,这是因为注册表的独特优点,使应用程序和系统都把许多参数和初始化信息存放进了注册表中。但在某些场合,INI文件还拥有不可替代的地位。
1.6 分类
在Windows操作系统中存在两个INI文件:SYSTEM.INI和WIN.INI。在纯文本处理器或DOS编辑器中打开INI文件就可能知道这些文件大概要做什么。这些文件中包括对鼠标、键盘、外围设备,显示器颜色,密码等的变量参数的设置声明。在正常情况下,这些文件在文本编辑器中不能被改动(如文本编辑器在关闭之前显示“保存修改”,这时点击“否”)。
在Windows 95、98、NT及之后的版本中,大部分的设置是通过对注册表的修改实现的,而不是通过使用INI文件。某些程序包含自己的INI文件,这些文件的内容的修改通常是通过该程序的用户界面来更改程序的特征,并不是通过编辑文件本身来进行的。
以我个人的使用经验来讲,通常将IOT和服务器相关的配置信息写入到ini配置文件,然后ini配置文件的路径通过系统环境变量XXX_CONFIG_PATH来进行动态指定(而不是代码固化,当然代码会有一个默认路劲),这样给我们的应用程序提供了非常大的灵活度。
二、一个轻量级ini文件解析库:IniFile2
ini文件是一种常见的配置文件。它以简单的文字与简单的结构组成.INI文件会以不同的扩展名,如".ini.",".cfg",".conf"等。
2.1 INI文件的格式
INI文件由3个重要的部分组成:参数(parameters),段(sections)和注释(comments).其格式如下:
- 段(sections)
[section]
- 参数(parameters)
name=value
- 注释(comments)
;comments
每个段包括段名,注释,和一定的参数对,段名不可重复。段内的参数对是有序的,可重复的。注释一般以分号“;”开头,在分号后面的文字,直到该行结尾都全部为注解。但是也有很多的配置文件的注释是以“#”开头的。
【重要说明】:
一般来说,段与段直接的名字是不能重复的。而段内的参数对是有序的,可重复的。虽然这种重复参数的情况比较少,但是有些地方还是会用到的。如OceanBase数据库的 Schema配置文件如下。
[sys_table]
table_id=1
max_column_id=11
table_type=1
#rowkey is table name
rowkey_is_fixed_length=0
column_info=table_name,varchar,128
column_info=table_id,int
column_info=table_type,int
column_info=rowkey_len,int
column_info=max_column_id,int
INI文件不一定有段名,通常此时会为其增加一个默认的段名。
示例中存在段名,段名为sys_table,在配置文件中不能再存在其他sys_table段,而该段中的存在多个column_info参数,每个参数表示sys_table中的一个字段的信息。参数rowkey_is_fixed_length还带有注释。
注释是提高配置文件可读性的重要方法。在解析的过程中一般会被忽略。但是如果你准备给你的解析库添加一个保存到文件的功能的话,就应该考虑到用户可能会为每个参数或者段添加注释的可能性。
1.2 IniFile2的接口设计
接口设计必须要保证足够的稳定性和易用性。INI配置文件通常是启动时读,一旦启动程序,中途几乎不会修改配置文件。所以一个简单的解析库,首要目标是解决INI文件的解析,然后是在内存中修改内容,以及将内存修改后的内容保存到INI文件中去。
完整的解析至少要包括以下功能:
- 打开并解析一个名为fname的INI文件
int Load(const string &fname);
- 获取section段第一个键为key的string/int/double/bool值,成功返回0,否则返回错误码
int GetStringValue(const string §ion, const string &key, string *value);
int GetIntValue(const string §ion, const string &key, int *value);
int GetDoubleValue(const string §ion, const string &key, double *value);
int GetBoolValue(const string §ion, const string &key, bool *value);
- 获取section段第一个键为key的string/int/double/bool值,成功返回获取的值,否则返回默认值
void GetStringValueOrDefault(const string §ion, const string &key, string *value, const string &defaultValue);
void GetIntValueOrDefault(const string §ion, const string &key, int *value, int defaultValue);
void GetDoubleValueOrDefault(const string §ion, const string &key, double *value, double defaultValue);
void GetBoolValueOrDefault(const string §ion, const string &key, bool *value, bool defaultValue);
- 修改section段指定key的string/int/double/bool值
int SetStringValue(const string §ion, const string &key, const string &value);
int SetIntValue(const string §ion, const string &key, int value);
int SetDoubleValue(const string §ion, const string &key, double value);
int SetBoolValue(const string §ion, const string &key, bool value);
- 获取section段所有键为key的值,并将值赋到values的vector中
int GetValues(const string §ion, const string &key, vector<string> *values);
- 将内容保存到当前文件
int Save();
- 将内容另存到一个名为fname的文件
int SaveAs(const string &fname);
同时还应该具有相关判断的功能:
- 获取section个数,至少存在一个空section
int GetSectionNum();
- 获取section列表,并返回section个数
int GetSections(vector<string> *sections);
- 是否存在某个section
bool HasSection(const string §ion);
- 是否存在某个key
bool HasKey(const string §ion, const string &key);
与此之外,IniFile2还为我们提供了(我个人认为基本不需要,因为配置文件是根据系统量身定制好的):
- 删除段
void DeleteSection(const string §ion);
- 删除特定段的特定参数
void DeleteKey(const string §ion, const string &key);
- 设置注释标记符列表
void SetCommentHead(const string &head);
1.3 IniFile2的特点
- 支持解析ini文件
- 支持修改、保存ini文件
- 支持设置多个注释符,默认为“#”和';'
- 支持参数名重复
IniFile库既包含了INI文件的解析,也能够修改并保存INI文件。
解析过程中如果INI文件中没有指定段名,则会指定一个空字符串作为段名,段采用map保存,而段中的参数则采用vector保存,因此支持参数名重复。
IniFile除了适合用在一般后台程序读取配置文件,也能够帮助GUI界面程序提供参数配置,修改,保存等。
1.4 IniFile2的使用
使用很简单生成一个ini文件test.ini
cat > test.ini
#this is commit
;this is commit
[COMMON]
DB = mysql
PASSWD=root
首先指定头文件和命名空间然后使用open函数打开ini文件getValue可以获取指定段的指定项的值:
#include "inifile.h"
using namespace inifile;
filepath = "test.ini";
IniFile ini;
ini.open(filepath);
//获取指定段的指定项的值
string db_name = ini.getValue("COMMON","DB");
//设置新值和注释
ini.setValue("TEST","NAME","root","用户名称");
//保存到文件
ini.save();
有需要源码的可以私下联系我哟 ^ - ^ 。
网友评论