C/C++ 操作ini文件(SinpleIni 跨平台库)


  最近在学习时,发现自己还不会操作ini文件,想着以前工作时接触到的项目或多或少都要用到ini文件去保存初始化程序的数据;所以赶紧去网上搜索以下C/C++操作ini文件都有些什么库可以玩玩;搜索到有:

  1. inih:这是C语言小巧的库,更适合嵌入式开发;

  2. iniparser:这是C语言的库,挺方便使用的,开源,两个.h文件和两个文件,但只能在Linux中使用;

  3. simpleini:这是C++的库,挺方便使用的,跨平台,开源,就两个.h文件和一个文件,且支持中文;

  所以最后我选择了simpleini这个库去学习使用!

一、介绍

1. ini介绍

  ini文件由 [section]节点和key键和value值构成。

  例如一个简单的ini文件如下所示:

1 [message] 2 name = 张三 3 age = 25 4 height = 173.2 5 6 ; 这是一个注释 7 8 [server] 9 ip = 127.0.0.1 10 port = 6666

  message就是节点,节点下方就是它的键和值;server也是一个节点。

  如果需要注释,使用英文分号 ' ; ' 即可。

2. simpleini介绍

  一个跨平台库,提供了一个简单的API来读取和写入ini风格的配置文件。它支持ASCII、MBCS和Unicode格式的数据文件。它被明确设计为可移植到任何平台,并已在Windows, WinCE和Linux上进行了测试。使用MIT`许可证作为开源和免费发布.

功能概述

  • MIT许可允许在所有软件中免费使用(包括GPL和商业软件)
  • 多平台(Windows 95到Windows 10、Windows CE、Linux、Unix)
  • 加载和保存ini风格的配置文件
  • 在所有平台上,配置文件可以使用任何换行格式
  • 对文件格式的自由接受
  • 没有section的键/值,没有值的键
  • 删除部分、键和值周围的空白
  • 支持多行值(嵌入换行字符的值)
  • 可选支持同名的多个键
  • 可选的不区分大小写的节和键(仅针对ASCII字符)
  • 在文件加载时以相同的顺序保存部分和键
  • 尽可能保留文件、节和键上的注释
  • 同时支持char或wchar_t编程接口
  • 同时支持MBCS(系统区域设置)和UTF8文件编码
  • 在Linux/Unix上,系统区域设置不需要是UTF8才能加载UTF8文件
  • 在节、键、值和注释中支持非ascii字符
  • 通过用户编写的转换器类支持非标准字符类型或文件编码
  • 支持以编程方式添加/修改值
  • 在大多数编译器中应该编译没有警告

二、下载

  GitHub链接:github/brofield/simpleini
  GitHub brofield/simpleini: Crossplatform C++ library providing a simple API to read and write INIstyle configuration files

下载后解压

这三个文件可在 Window 或 Linux 环境去使用!

三、使用

以下介绍的用法,Linux和Window环境均可使用!

包含头文件:

#include "SimpleIni.h"

#define FILE_NAME "./test1.ini"

test1.ini内容如下:

1. 加载ini文件

1 // 定义ini文档对象 2 CSimpleIniA ini; 3 4 // 加载ini文件 5 SI_Error rc; 6 rc = ini.LoadFile(FILE_NAME); // 另一种方式:SI_Error LoadFile(FILE * a_fpFile); 7 if (rc < 0)

rc返回值有以下这些:

1 using SI_Error = int; 2 3 constexpr int SI_OK = 0; //!< No error 4 constexpr int SI_UPDATED = 1; //!< An existing value was updated 5 constexpr int SI_INSERTED = 2; //!< A new value was inserted 6 7 // note: test for any error with (retval < 0) 8 constexpr int SI_FAIL = 1; //!< Generic failure 9 constexpr int SI_NEM = 2; //!< Out of memory error 10 constexpr int SI_FILE = 3; //!< File error (see errno for detail error)

2. 简单配置

1 // 设置INI数据的存储格式,参数为true时保存为UTF8格式,否则为本地编码格式 2 ini.SetUnicode(true); 3 4 // 是否允许一个关键字对应多个值,默认为允许;若不允许,则将最后一个值作为此关键字关联的值 5 ini.SetMultiKey(false);

3. 增

SetValue

参数一:节点

参数二:键

参数三:值

返回值:SI_Error (也就是int类型)

1).添加一个新的节点(section)

1 // 添加一个新的 section 2 rc = ini.SetValue("section1", nullptr, nullptr); 3 if (rc < 0)

2). 添加一个新的 key和value

1 // 添加一个新的 key和value 2 rc = ini.SetValue("section1", "name", "张三"); 3 if (rc < 0) 7 //const char *name = ini.GetValue("section1", "name", ""); 8 //printf("name = %s\n", name); 9 10 ini.SetValue("section1", "age", "24"); 11 ini.SetValue("section1", "sex", "男");

注意:如果name存在,则会将name键(key)对应的值(value)修改为张三;

还可以使用SetLongValue、SetDoubleValue、SetBoolValue去添加:

1 ini.SetLongValue("server", "length", 173); 2 ini.SetDoubleValue("server", "weight", 53.5); 3 ini.SetBoolValue("server", "vip", true);

4. 改

SetValue

参数一:节点

参数二:键

参数三:值

返回值:SI_Error (也就是int类型)

1).修改值(value)

1 // 修改value,如果键(name)不存在则添加该 key和value 2 rc = ini.SetValue("section1", "name", "李四"); 3 if (rc < 0) 7 //const char *name = ini.GetValue("section1", "name"); 8 //printf("name = %s\n", name);

注意:如果要修改的值对应的键不存在,则会添加改键和值到section1节点中!

貌似无法修改节点(section) 和 键(key),我没有找到相关的api。。。

还可以使用SetLongValue、SetDoubleValue、SetBoolValue去添加:

1 ini.SetLongValue("server", "length", 1000); 2 ini.SetDoubleValue("server", "weight", 66.66); 3 ini.SetBoolValue("server", "vip", false);

5. 删

Delete

参数一:节点

参数二:键

返回值:bool

booldone=false;

1).删除 key 和 value

1 // 删除 key 2 done = ini.Delete("section1", "name"); 3 if (false == done)

2). 当最后一个key也被删除掉后,section1也会被删除

1 // 如果最后一个key也被删除了,那么section也会被一起删除掉 2 bool deleteSectionIfEmpty = true; 3 done = ini.Delete("section1", "age", deleteSectionIfEmpty); 4 if (false == done)

此时section1中还由两个key,随意上面的代码执行后只会将age给删除掉,并不会也把section1删掉;

如果将Delete的第三个参数值true去删除sex,那么section1也会一并删掉!

ini.Delete("section1", "sex", true);

将section1还原到一开始的的样子 ,方便下面第3点操作删除

3).删除整个节点(section)和其下的所有键(key)

1 // 删除整个section和其中的所有键 2 done = ini.Delete("section1", nullptr); 3 if (false == done)

执行如上代码,就会将刚刚还原的section1都给删除掉!

6. 查

GetValue

参数一:节点

参数二:键

参数三:如果没找到,返回参数三指定的默认值

返回值:const char *

1). 将下图中的ini文件内容读取打印显示

1 int _int = std::stoi(ini.GetValue("section", "_int", "1")); 2 printf("_int = %d\n", _int); 3 4 long long _long = std::stoll(ini.GetValue("section", "_long", "1")); 5 printf("_long = %lld\n", _long); 6 7 double _double = std::stod(ini.GetValue("section", "_double", "0.0")); 8 printf("_double = %lf\n", _double); 9 10 float _float = std::stof(ini.GetValue("section", "_float", "0.0")); 11 printf("_float = %f\n", _float); 12 13 bool _bool = ini.GetBoolValue("section", "_bool", false); 14 printf("_bool = %s\n", _bool ? "true" : "false"); 15 16 std::string _string = ini.GetValue("section", "_string", ""); 17 printf("_string = %s\n", _string_str()); 18 19 std::string _string2 = ini.GetValue("section", "_string2", ""); 20 printf("_string2 = %s\n", _string2_str()); 21 22 char _char = ini.GetValue("section", "_char", "")[0]; 23 printf("_char = %c\n", _char); 24 25 std::string ip = ini.GetValue("server", "ip", "0.0.0.0"); 26 printf("ip = %s\n", ip_str()); 27 28 int port = std::stoi(ini.GetValue("server", "port", "1")); 29 printf("port = %d\n", port); 30 31 std::string name1 = ini.GetValue("server", "name", ""); 32 printf("name = %s\n", name1_str());

还可以使用GetLongValue、GetDoubleValue、GetBoolValue去查:

1 int lenght = ini.GetLongValue("server", "length", 1); 2 double weight = ini.GetDoubleValue("server", "weight", 1); 3 bool vip = ini.GetBoolValue("server", "vip", false);

2). 遍历ini文件的所有内容

GetAllSections:获取所有节点,参数一引用返回list链表;

GetSection:根据参数字符串,获取节点,返回multimap容器;

1 CSimpleIniA::TNamesDepend sections; 2 // get all sections 3 ini.GetAllSections(sections); 4 // 遍历所有 section 的 key 和 value 5 for (const auto &it : sections) 11 } 12 }

3). 遍历所有节点(section)

1 CSimpleIniA::TNamesDepend sections1; 2 // 获取所有section 3 ini.GetAllSections(sections1); 4 // 遍历所有 sections 5 for (const auto &it : sections1)

4). 遍历指定节点的键(key)

GetAllKeys:获取所有键,参数二引用返回list链表;

1 CSimpleIniA::TNamesDepend keys; 2 // get all keys in a section 3 ini.GetAllKeys("section", keys); 4 // 遍历 section 指定的所有 key 5 for (const auto &it : keys)

5). 获取一个键对应多个值

首先,ini.SetMultiKey(true);得设置为true,否则只会获取到最后一个值,其他会被删除掉;

在ini文件中的server节点添加多几个name键

使用以下代码获取:

1 CSimpleIniA::TNamesDepend values; 2 // 获取 key 所对应的多个 value;ini.SetMultiKey(true);一定要设置为true, 3 // 否则就只会获取到最后一个,其他删除 4 ini.GetAllValues("server", "name", values); 5 // 遍历一个 key 对应多个 value; 6 for (const auto &it : values)

6).获取指定节点(section)里有多少键值

1 // 获取section里有多少值 2 int size = ini.GetSectionSize("section"); 3 printf("section 的 key 个数:%d\n", size);

7. 保存

注意:以上增、删、改,只有执行保存代码后,才会在文件做出相应的修改!

1). 保存到文件

1 /* 保存到文件中 */ 2 rc = ini.SaveFile(FILE_NAME); 3 if (rc < 0)

2). 保存到C++字符串

1 std::string strIni = ""; 2 ini.Save(strIni); 3 printf("%s\n", strIni_str());

8. 中文乱码问题

window环境写入或者读取中文有乱码现象,将文件编码改成ANSI编码即可!

可以使用notepad++去修改,如下图:

Linux环境出现中文乱码问题,那就新建一个文件,然后再手动敲上需要的信息即可,例如touch test1.ini 或 vim test1.ini

记得,千万别从从Window拷贝进Linux中,文件中是不会显示出乱码,但是读取写入时会有乱码!

我遇到的乱码问题,通过上面的方法就可以解决了!

四、封装

  可以根据自己项目的具体需求去封装成方便调用的接口去使用!

  例如我下面的用法:

  configdef.h

  这个是定义结构体的头文件,从ini文件中读取的数据都存放在结构体中!

1 #ifndef _CMON_CONFIGDEF_H_ 2 #define _CMON_CONFIGDEF_H_ 3 4 #include <string> 5 6 typedef struct st_env_config 26 st_env_config(int _int, long _long, double _double, float _float, bool _bool, std::string _string, char _char, std::string _ip, unsigned short _port) 38 39 // 赋值运算符重载 40 st_env_config &operator=(const st_env_config &config) 53 54 return *this; 55 } 56 57 }_st_env_config; 58 59 #endif // _CMON_CONFIGDEF_H_

iniconfig.h

这个是封装simpleini的头文件

1 #ifndef _CMON_INICONFIG_H_ 2 #define _CMON_INICONFIG_H_ 3 4 #include <string> 5 6 #include "configdef.h" 7 8 #include "../simpleini/SimpleIni.h" 9 10 11 12 class Iniconfig ; 77 78 #endif // _CMON_INICONFIG_H_

iniconfigpp

这个是封装simpleini的cpp文件内容

1 #include "iniconfig.h" 2 3 #include <stdio.h> 4 #include <iostream> 5 6 7 Iniconfig::Iniconfig() : _isloaded(false) 13 14 Iniconfig::Iniconfig(const std::string & path, st_env_config &config) 27 28 int _int = getLongValue("section", "_int", 1); 29 long _long = getLongValue("section", "_long", 1); 30 double _double = getDoubleValue("section", "_double", 0.0); 31 float _float = getDoubleValue("section", "_float", 0.0); 32 bool _bool = getBoolValue("section", "_bool", false); 33 std::string _string = getValue("section", "_string", ""); 34 char _char = getValueC("section", "_char", '\0'); 35 std::string ip = getValue("server", "ip", "0.0.0.0"); 36 unsigned short port = getLongValue("section", "port", 1); 37 38 config = st_env_config(_int, _long, _double, _float, _bool, _string, _char, ip, port); 39 40 _isloaded = true; 41 } 42 43 Iniconfig::~Iniconfig() 46 47 // 加载ini文件 48 bool Iniconfig::loadfile(const std::string &path) 58 59 _isloaded = true; 60 61 } 62 return _isloaded; 64 } 65 66 bool Iniconfig::saveFile(const std::string & fileName) 73 74 _isloaded = false; 75 76 return true; 77 } 78 79 void Iniconfig::setUnicode(const bool utf8) 82 83 void Iniconfig::setMultiKey(const bool multKey) 86 87 bool Iniconfig::getData(st_env_config & config) 103 104 return false; 105 } 106 107 std::string Iniconfig::getIniStr() 116 } 117 118 return str; 119 } 120 121 bool Iniconfig::addSection(const std::string & section) 124 125 SI_Error rc = _ini.SetValue(section_str(), nullptr, nullptr); 126 if (rc < 0) 130 131 return true; 132 } 133 134 bool Iniconfig::addValue(const std::string & section, const std::string & key, const std::string & value) 136 137 SI_Error rc = _ini.SetValue(section_str(), key_str(), value_str()); 138 if (rc < 0) 142 143 return true; 144 } 145 146 bool Iniconfig::addLongValue(const std::string & section, const std::string & key, const long value) 148 149 SI_Error rc = _ini.SetLongValue(section_str(), key_str(), value); 150 if (rc < 0) 154 155 return true; 156 } 157 158 bool Iniconfig::addDoubleValue(const std::string & section, const std::string & key, const double value) 160 161 SI_Error rc = _ini.SetDoubleValue(section_str(), key_str(), value); 162 if (rc < 0) 166 167 return true; 168 } 169 170 bool Iniconfig::addBoolValue(const std::string & section, const std::string & key, const bool value) 172 173 SI_Error rc = _ini.SetBoolValue(section_str(), key_str(), value); 174 if (rc < 0) 178 179 return true; 180 } 181 182 bool Iniconfig::setValue(const std::string & section, const std::string & key, const std::string & value) 184 185 SI_Error rc = _ini.SetValue(section_str(), key_str(), value_str()); 186 if (rc < 0) 190 191 return true; 192 } 193 194 bool Iniconfig::setLongValue(const std::string & section, const std::string & key, const long value) 196 197 SI_Error rc = _ini.SetLongValue(section_str(), key_str(), value); 198 if (rc < 0) 202 203 return true; 204 } 205 206 bool Iniconfig::setDoubleValue(const std::string & section, const std::string & key, const double value) 208 209 SI_Error rc = _ini.SetDoubleValue(section_str(), key_str(), value); 210 if (rc < 0) 214 215 return true; 216 } 217 218 bool Iniconfig::setBoolValue(const std::string & section, const std::string & key, const bool value) 220 221 SI_Error rc = _ini.SetBoolValue(section_str(), key_str(), value); 222 if (rc < 0) 226 227 return true; 228 } 229 230 bool Iniconfig::deleteKey(const std::string & section, const std::string & key) 232 233 bool done = false; 234 235 // 删除 key 236 done = _ini.Delete(section_str(), key_str()); 237 if (false == done) 241 242 return true; 243 } 244 245 bool Iniconfig::deleteKeys(const std::string & section, const std::string & key, const bool deleteSectionIfEmpty) 247 248 bool done = false; 249 250 done = _ini.Delete(section_str(), key_str(), deleteSectionIfEmpty); 251 if (false == done) 255 256 return true; 257 } 258 259 bool Iniconfig::deleteSection(const std::string & section) 261 262 bool done = false; 2 264 done = _ini.Delete(section_str(), nullptr); 265 if (false == done) 269 270 return true; 271 } 272 273 std::string Iniconfig::getValue(const std::string & section, const std::string & key, const std::string & defualtValue) 275 276 return _ini.GetValue(section_str(), key_str(), defualtValue_str()); 277 } 278 279 char Iniconfig::getValueC(const std::string & section, const std::string & key, const char & defualtValue) 281 282 std::string str = std::to_string(defualtValue); 283 return _ini.GetValue(section_str(), key_str(), str_str())[0]; 284 } 285 286 long Iniconfig::getLongValue(const std::string & section, const std::string & key, const short & defualtValue) 288 289 return _ini.GetLongValue(section_str(), key_str(), defualtValue); 290 } 291 292 double Iniconfig::getDoubleValue(const std::string & section, const std::string & key, const double & defualtValue) 294 295 return _ini.GetDoubleValue(section_str(), key_str(), defualtValue); 296 } 297 298 bool Iniconfig::getBoolValue(const std::string & section, const std::string & key, const bool & defualtValue) 300 301 return _ini.GetBoolValue(section_str(), key_str(), defualtValue); 302 } 303 304 int Iniconfig::getSectionSize(const std::string & section) 306 307 return _ini.GetSectionSize(section_str()); 308 } 309 310 void Iniconfig::printAll() 321 } 322 } 323 }

测试代码:

1 st_env_config config; 2 Iniconfig cof(FILE_NAME, config); 3 4 5 cof.addSection("abc"); 6 cof.addValue("abc", "name", "a"); 7 cof.addBoolValue("abc", "vip", true); 8 cof.addDoubleValue("abc", "length", 175.5); 9 cof.addLongValue("abc", "weight", 85); 10 11 cof.setValue("abc", "name", "b"); 12 cof.setBoolValue("abc", "vip", false); 13 cof.setDoubleValue("abc", "length", 188.8); 14 cof.setLongValue("abc", "weight", 90); 15 16 //cof.deleteKey("abc", "name"); 17 //cof.deleteKeys("abc", "vip"); 18 //cof.deleteSection("abc"); 19 20 printf("name = %c\n", cof.getValueC("abc", "name")); 21 printf("name = %s\n", cof.getValue("abc", "name")_str()); 22 printf("bool = %d\n", cof.getBoolValue("abc", "vip")); 23 printf("lenght = %f\n", cof.getDoubleValue("abc", "length")); 24 printf("weight = %ld\n", cof.getLongValue("abc", "weight")); 25 26 printf("%s\n", cof.getIniStr()_str()); 27 cof.saveFile(FILE_NAME);

五、总结
  simpleini库的基本用法如上面展示的那样,具体还有一些其他的api,现在还用不到,等用到了,再来补充!

  simpleini这个库应该也不算难,无非就是GetValue和SetValue的使用!

  ini文件常用来初始化程序,例如存储一些软件启动时初始化的一些基础数据,学习完这个库后,日后如果有写一些小软件就可以使用ini去初始化了!





上一篇:Qt 如何操作数据库SQL模块

下一篇:Qt 线程同步 QMutex、QReadWriteLock、QWaitCondition


C/C&#x2B;&#x2B;
Copyright © 2002-2019 k262电脑网 www.k262.cn 皖ICP备2020016292号
温馨提示:部分文章图片数据来源与网络,仅供参考!版权归原作者所有,如有侵权请联系删除!QQ:251442993 热门搜索 网站地图