简单的INI解析封装
简单封装的一个ini解析处理类(支持跨平台)。支持功能:
- 加载并解析指定ini文件中的配置;
- 读取指定 section 下的指定 key 的值。提示:支持按数值型读取,或按文本类型读取;
使用示例:
1 auto fWidth = 480.0f; 2 auto fHeight = 320.0f; 3 4 ns_ini::IniParser ini; 5 ini.open(strConfigFile.c_str()); 6 fWidth = ini.readFloat("glview", "screen_width", fWidth); 7 fHeight = ini.readFloat("glview", "screen_height", fHeight);
- 支持新段、项、值写入;提示:如果写入的项是已经存在的,则为修改旧项值;
示例:
1 auto fWidth = 480.0f; 2 auto fHeight = 320.0f; 3 4 ns_ini::IniParser ini; 5 ini.open(strConfigFile.c_str()); 6 fWidth = ini.readFloat("glview", "screen_width", fWidth); 7 fHeight = ini.readFloat("glview", "screen_height", fHeight); 8 9 ini.writeFloat("glview", "screen_height, 777.77f); // 将旧值修改为 777.77f 10 ini.writeInt("glview", "screen_height, 666); // 再次将旧值修改为 666 11 ini.writeText("glview", "screen_height, "jacc.kim"); // 再次将旧值修改为 文本"jacc.kim"
源码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /****************************************************************************** 2 3 I'm jacc.kim 4 5 CreateDate: 2017-06-13 17:12:16 6 FileName : JKIniParser.h 7 Version : 1.00 8 Author : jacc.kim 9 Summary : ini parser wrapper 10 11 ******************************************************************************/ 12 #pragma once 13 14 #include <list> 15 #include <map> 16 17 namespace ns_ini 18 { 19 20 class Section; 21 22 /****************************************************************************** 23 * create : (jacc.kim) [06-13-2017] 24 * summary : class IniParser 25 ******************************************************************************/ 26 class IniParser 27 { 28 public: 29 void setIniFile(const char* const pcszIniFile); 30 bool open(const char* const pcszIniFile = nullptr); 31 bool save(const char* const pcszIniFile = nullptr); 32 void close(); 33 34 unsigned int getSectionAmount() const; 35 bool isSectionExisted(const char* const pcszSection) const; 36 bool isParameterExisted(const char* const pcszSection, const char* const pcszParameter) const; 37 38 int readInt(const char* const pcszSection, const char* const pcszKey, const int def = 0) const; 39 unsigned int readUnsignedInt(const char* const pcszSection, const char* const pcszKey, const unsigned int def = 0u) const; 40 bool readBool(const char* const pcszSection, const char* const pcszKey, const bool def = false) const; 41 float readFloat(const char* const pcszSection, const char* const pcszKey, const float def = 0.0f) const; 42 double readDouble(const char* const pcszSection, const char* const pcszKey, const double def = 0.0) const; 43 const char* readText(const char* const pcszSection, const char* const pcszKey, const char* const def = nullptr) const; 44 45 // !!!note: write existed section & key, the old value will be replaced. 46 void writeInt(const char* const pcszSection, const char* const pcszKey, const int value); 47 void writeUnsignedInt(const char* const pcszSection, const char* const pcszKey, const unsigned int value); 48 void writeBool(const char* const pcszSection, const char* const pcszKey, const bool value); 49 void writeFloat(const char* const pcszSection, const char* const pcszKey, const float value); 50 void writeDouble(const char* const pcszSection, const char* const pcszKey, const double value); 51 void writeText(const char* const pcszSection, const char* const pcszKey, const char* const value); 52 53 bool remove(const char* const pcszSection, const char* const pcszKey); 54 bool remove(const char* const pcszSection); 55 void clear(); 56 57 public: 58 IniParser(); 59 ~IniParser(); 60 61 Section* getSection(const char* const pcszSection) const; 62 Section& operator[](const char* const pcszSection) const; 63 64 private: 65 IniParser(const IniParser& rhs)/* = delete*/; 66 IniParser& operator=(const IniParser& rhs)/* = delete*/; 67 68 void trimLeft(char*& p, char*& q); 69 void trimRight(char*& p, char*& q); 70 void trim(char*& p, char*& q); 71 void trimRN0(char*& p, char*& q); 72 bool isEndWithN(const char* p, const size_t nLength); 73 bool stringEqual(const char* p, const char* q, int nChar = INT_MAX) const; 74 bool isSectionName(char* p, char* q); 75 char* splitKeyValue(char* p, char* q); 76 void parseIniLine(char* szIniLine); 77 void addSection(char* szSectionName); 78 void addParameter(char* szKey, char* szValue); 79 80 private: 81 typedef std::list<Section*> SectionList; 82 typedef SectionList::iterator SectionListIter; 83 84 // key = section name, value = section's ptr 85 typedef std::map <std::string, SectionListIter> SectionMap; 86 87 private: 88 std::string m_strIniFile; // ini file name 89 SectionList m_listSections; // all sections. 90 SectionMap m_mapSectionName; // section <--> index mapping.(only reference.) 91 92 };//class IniParser 93 94 }//namespace ns_ini
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include "JKIniParser.h" 2 3 namespace ns_ini 4 { 5 6 /****************************************************************************** 7 * create : (jacc.kim) [06-13-2017] 8 * summary : class Section 9 ******************************************************************************/ 10 class Section 11 { 12 public: 13 struct Parameter 14 { 15 std::string key; 16 std::string value; 17 };//struct Parameter 18 19 typedef std::list<Parameter> ParameterList; 20 typedef ParameterList::iterator ParameterListIter; 21 typedef std::map<std::string, ParameterListIter> ParameterMap; 22 23 public: 24 Section(const char* pcszSectionName) : m_strSectionName (pcszSectionName) 25 , m_listParameters () 26 , m_mapParameterKeys() 27 {} 28 29 ~Section() { 30 this->clear(); 31 } 32 33 const char* getSectionName() const { 34 return m_strSectionName.c_str(); 35 } 36 37 bool isParameterExisted(const char* const pcszKey) const { 38 return m_mapParameterKeys.find(pcszKey) != m_mapParameterKeys.end(); 39 } 40 41 Parameter& operator[](const char* const pcszKey) const { 42 auto iter = m_mapParameterKeys.find(pcszKey); 43 return *(iter->second); 44 } 45 46 const char* read(const char* const pcszKey) { 47 const char* pcszRetValue = nullptr; 48 if (nullptr != pcszKey) { 49 auto iter = m_mapParameterKeys.find(pcszKey);; 50 if (m_mapParameterKeys.end() != iter) { 51 pcszRetValue = (*(iter->second)).value.c_str(); 52 } 53 } 54 return pcszRetValue; 55 } 56 57 bool write(const char* const pcszKey, const char* const pcszValue) { 58 auto iter = m_mapParameterKeys.find(pcszKey); 59 if (m_mapParameterKeys.end() == iter) { 60 Parameter param = { pcszKey, pcszValue }; 61 m_listParameters.emplace_back(param); 62 m_mapParameterKeys[pcszKey] = --m_listParameters.end(); 63 return true; 64 } 65 (*this)[pcszKey].value = pcszValue; 66 return true; 67 } 68 69 bool remove(const char* pcszKey) { 70 auto bIsSuccess = false; 71 if (nullptr != pcszKey) { 72 auto iter = m_mapParameterKeys.find(pcszKey); 73 if (m_mapParameterKeys.end() != iter) { 74 m_listParameters.erase(iter->second); 75 m_mapParameterKeys.erase(iter); 76 bIsSuccess = true; 77 } 78 } 79 return bIsSuccess; 80 } 81 82 void clear() { 83 m_listParameters.clear(); 84 m_mapParameterKeys.clear(); 85 } 86 87 ParameterList& getAllParameters() { 88 return m_listParameters; 89 } 90 91 private: 92 std::string m_strSectionName; 93 ParameterList m_listParameters; 94 ParameterMap m_mapParameterKeys; 95 96 };//class Section 97 98 /////////////////////////////////////////////////////////////////////////////// 99 // class IniParser 100 IniParser::IniParser() : m_strIniFile ("") 101 , m_listSections () 102 , m_mapSectionName() 103 { 104 105 } 106 107 IniParser::~IniParser() { 108 this->clear(); 109 } 110 111 void IniParser::setIniFile(const char* const pcszIniFile) { 112 if (nullptr == pcszIniFile) { 113 return; 114 } 115 m_strIniFile = pcszIniFile; 116 } 117 118 bool IniParser::open(const char* const pcszIniFile/* = nullptr*/) { 119 auto bIsSuccess = false; 120 const char* pcszOpenFile = nullptr != pcszIniFile ? pcszIniFile : m_strIniFile.c_str(); 121 if (nullptr == pcszOpenFile) { 122 return bIsSuccess; 123 } 124 if (nullptr != pcszIniFile) { 125 this->setIniFile(pcszIniFile); 126 } 127 this->clear(); 128 auto pINIFile = fopen(pcszIniFile, "rb"); 129 if (nullptr != pINIFile) { 130 bIsSuccess = true; 131 const size_t nBUFF_SIZE = 2048; 132 char szBuff[nBUFF_SIZE]; 133 while (!feof(pINIFile)) { 134 memset((void*)szBuff, 0x0L, nBUFF_SIZE); 135 fgets(szBuff, nBUFF_SIZE, pINIFile); 136 this->parseIniLine(szBuff); 137 } 138 fclose(pINIFile); 139 pINIFile = nullptr; 140 } 141 142 return bIsSuccess; 143 } 144 145 bool IniParser::save(const char* const pcszIniFile/* = nullptr*/) { 146 auto bIsSuccess = false; 147 const char* pcszSaveFile = nullptr != pcszIniFile ? pcszIniFile : m_strIniFile.c_str(); 148 if (nullptr == pcszSaveFile) { 149 return bIsSuccess; // 没有可保存的路径 150 } 151 ::remove(pcszSaveFile); 152 auto pINIFile = fopen(pcszSaveFile, "ab+"); 153 if (nullptr != pINIFile) { 154 bIsSuccess = true; 155 auto iter = m_listSections.begin(); 156 const auto iterend = m_listSections.end(); 157 const size_t nBUFF_SIZE = 2048; 158 char szBuffer[nBUFF_SIZE]; 159 Section* pSection = nullptr; 160 for (; iterend != iter;/* ++iter*/) { 161 pSection = *iter; 162 const char* pcszSectionName = pSection->getSectionName(); 163 fputs("[", pINIFile); 164 fputs(pcszSectionName, pINIFile); 165 fputs("]\r\n", pINIFile); 166 auto& allParameters = (*iter)->getAllParameters(); 167 auto listiter = allParameters.begin(); 168 const auto listiterend = allParameters.end(); 169 for (; listiterend != listiter; ++listiter) { 170 auto& param = *listiter; 171 memset((void*)szBuffer, 0x0L, nBUFF_SIZE); 172 memcpy(szBuffer, param.key.c_str(), param.key.length()); 173 szBuffer[param.key.length()] = '='; 174 memcpy(szBuffer + param.key.length() + 1, param.value.c_str(), param.value.length()); 175 const auto nEndPos = param.key.length() + 1 + param.value.length(); 176 szBuffer[nEndPos + 1] = '\0'; 177 fputs(szBuffer, pINIFile); 178 if (!this->isEndWithN(szBuffer, nEndPos + 1)) { 179 fputs("\r\n", pINIFile); 180 } 181 } 182 if (iterend != ++iter) { 183 fputs("\r\n", pINIFile); 184 } 185 } 186 fclose(pINIFile); 187 pINIFile = nullptr; 188 } 189 190 return bIsSuccess; 191 } 192 193 void IniParser::close() { 194 this->save(); 195 this->clear(); 196 this->setIniFile(nullptr); 197 } 198 199 unsigned int IniParser::getSectionAmount() const { 200 return static_cast<unsigned int>(m_listSections.size()); 201 } 202 203 bool IniParser::isSectionExisted(const char* const pcszSection) const { 204 return nullptr != this->getSection(pcszSection); 205 } 206 207 bool IniParser::isParameterExisted(const char* const pcszSection, const char* const pcszParameter) const { 208 auto pSection = this->getSection(pcszSection); 209 return nullptr != pSection && pSection->isParameterExisted(pcszParameter); 210 } 211 212 int IniParser::readInt(const char* const pcszSection, const char* const pcszKey, const int def/* = 0*/) const { 213 int retValue = def; 214 const char* pcszText = this->readText(pcszSection, pcszKey, nullptr); 215 if (nullptr != pcszText) { 216 if (1 != sscanf(pcszText, "%d", &retValue)) { 217 retValue = def; // 读取失败. 218 } 219 } 220 return retValue; 221 } 222 223 unsigned int IniParser::readUnsignedInt(const char* const pcszSection, const char* const pcszKey, const unsigned int def/* = 0u*/) const { 224 unsigned int retValue = def; 225 const char* pcszText = this->readText(pcszSection, pcszKey, nullptr); 226 if (nullptr != pcszText) { 227 if (1 != sscanf(pcszText, "%u", &retValue)) { 228 retValue = def; // 读取失败. 229 } 230 } 231 return retValue; 232 } 233 234 bool IniParser::readBool(const char* const pcszSection, const char* const pcszKey, const bool def/* = false*/) const { 235 bool retValue = def; 236 const char* pcszText = this->readText(pcszSection, pcszKey, nullptr); 237 if (nullptr != pcszText) { 238 int iTempVal = 0; 239 if (1 == sscanf(pcszText, "%d", &iTempVal)) { 240 return 0 == iTempVal ? false : true; 241 } else if (this->stringEqual(pcszText, "true")) { 242 return true; 243 } else { 244 return false; 245 } 246 } 247 return retValue; 248 } 249 250 float IniParser::readFloat(const char* const pcszSection, const char* const pcszKey, const float def/* = 0.0f*/) const { 251 float retValue = def; 252 const char* pcszText = this->readText(pcszSection, pcszKey, nullptr); 253 if (nullptr != pcszText) { 254 if (1 != sscanf(pcszText, "%f", &retValue)) { 255 retValue = def; // 读取失败. 256 } 257 } 258 return retValue; 259 } 260 261 double IniParser::readDouble(const char* const pcszSection, const char* const pcszKey, const double def/* = 0.0*/) const { 262 double retValue = def; 263 const char* pcszText = this->readText(pcszSection, pcszKey, nullptr); 264 if (nullptr != pcszText) { 265 if (1 != sscanf(pcszText, "%lf", &retValue)) { 266 retValue = def; // 读取失败. 267 } 268 } 269 return retValue; 270 } 271 272 const char* IniParser::readText(const char* const pcszSection, const char* const pcszKey, const char* const def/* = nullptr*/) const { 273 const char* pcszRetValue = def; 274 auto pSection = this->getSection(pcszSection); 275 if (nullptr != pSection) { 276 pcszRetValue = pSection->read(pcszKey); 277 } 278 return pcszRetValue; 279 } 280 281 void IniParser::writeInt(const char* const pcszSection, const char* const pcszKey, const int value) { 282 const size_t nBUFF_SIZE = 256; 283 char szBuff[nBUFF_SIZE]; 284 memset((void*)szBuff, 0x0L, nBUFF_SIZE); 285 sprintf(szBuff, "%d", value); 286 this->writeText(pcszSection, pcszKey, szBuff); 287 } 288 289 void IniParser::writeUnsignedInt(const char* const pcszSection, const char* const pcszKey, const unsigned int value) { 290 const size_t nBUFF_SIZE = 256; 291 char szBuff[nBUFF_SIZE]; 292 memset((void*)szBuff, 0x0L, nBUFF_SIZE); 293 sprintf(szBuff, "%u", value); 294 this->writeText(pcszSection, pcszKey, szBuff); 295 } 296 297 void IniParser::writeBool(const char* const pcszSection, const char* const pcszKey, const bool value) { 298 const size_t nBUFF_SIZE = 256; 299 char szBuff[nBUFF_SIZE]; 300 memset((void*)szBuff, 0x0L, nBUFF_SIZE); 301 sprintf(szBuff, "%d", value ? 1 : 0); 302 this->writeText(pcszSection, pcszKey, szBuff); 303 } 304 305 void IniParser::writeFloat(const char* const pcszSection, const char* const pcszKey, const float value) { 306 const size_t nBUFF_SIZE = 256; 307 char szBuff[nBUFF_SIZE]; 308 memset((void*)szBuff, 0x0L, nBUFF_SIZE); 309 sprintf(szBuff, "%g", value); 310 this->writeText(pcszSection, pcszKey, szBuff); 311 } 312 313 void IniParser::writeDouble(const char* const pcszSection, const char* const pcszKey, const double value) { 314 const size_t nBUFF_SIZE = 256; 315 char szBuff[nBUFF_SIZE]; 316 memset((void*)szBuff, 0x0L, nBUFF_SIZE); 317 sprintf(szBuff, "%g", value); 318 this->writeText(pcszSection, pcszKey, szBuff); 319 } 320 321 void IniParser::writeText(const char* const pcszSection, const char* const pcszKey, const char* const value) { 322 if (nullptr != pcszSection && nullptr != pcszKey && nullptr != value) { 323 auto iter = m_mapSectionName.find(pcszSection); 324 Section* pSection = nullptr; 325 if (m_mapSectionName.end() == iter) { 326 pSection = new (std::nothrow) Section(pcszSection); 327 if (nullptr == pSection) { 328 return; 329 } 330 m_listSections.emplace_back(pSection); 331 m_mapSectionName[pcszSection] = --m_listSections.end(); 332 } else { 333 pSection = *(iter->second); 334 } 335 pSection->write(pcszKey, value); 336 } 337 } 338 339 bool IniParser::remove(const char* const pcszSection, const char* const pcszKey) { 340 auto bIsSuccess = false; 341 if (nullptr != pcszSection) { 342 auto iter = m_mapSectionName.find(pcszSection); 343 if (m_mapSectionName.end() != iter) { 344 auto pSection = *(iter->second); 345 if (nullptr != pSection) { 346 bIsSuccess = pSection->remove(pcszKey); 347 } 348 } 349 } 350 return bIsSuccess; 351 } 352 353 bool IniParser::remove(const char* const pcszSection) { 354 auto bIsSuccess = false; 355 if (nullptr != pcszSection) { 356 auto iter = m_mapSectionName.find(pcszSection); 357 if (m_mapSectionName.end() != iter) { 358 auto list_iter = iter->second; 359 Section* pSection = *list_iter; 360 if (nullptr != pSection) { 361 delete pSection; 362 pSection = nullptr; 363 } 364 m_listSections.erase(list_iter); 365 m_mapSectionName.erase(iter); 366 bIsSuccess = true; 367 } 368 } 369 return bIsSuccess; 370 } 371 372 void IniParser::clear() { 373 auto iter = m_listSections.begin(); 374 const auto iterend = m_listSections.end(); 375 Section* pSection = nullptr; 376 for (; iterend != iter; ++iter) { 377 pSection = *iter; 378 if (nullptr != pSection) { 379 delete pSection; 380 pSection = nullptr; 381 } 382 } 383 m_listSections.clear(); 384 m_mapSectionName.clear(); 385 } 386 387 Section* IniParser::getSection(const char* const pcszSection) const { 388 Section* pRetSection = nullptr; 389 auto iter = m_mapSectionName.find(pcszSection); 390 if (m_mapSectionName.end() != iter) { 391 pRetSection = *(iter->second); 392 } 393 return pRetSection; 394 } 395 396 Section& IniParser::operator[](const char* const pcszSection) const { 397 auto iter = m_mapSectionName.find(pcszSection); 398 return *(*(iter->second)); 399 } 400 401 void IniParser::trimLeft(char*& p, char*& q) { 402 if (nullptr != p) { 403 while (' ' == *p && ++p <= q); 404 } 405 } 406 407 void IniParser::trimRight(char*& p, char*& q) { 408 if (nullptr != q) { 409 while (' ' == *q && --q >= p); 410 } 411 } 412 413 void IniParser::trim(char*& p, char*& q) { 414 this->trimLeft(p, q); 415 this->trimRight(p, q); 416 } 417 418 void IniParser::trimRN0(char*& p, char*& q) { 419 if (nullptr != q) { 420 while (('\0' == *q || '\r' == *q || '\n' == *q) && --q >= p); 421 } 422 } 423 424 bool IniParser::isEndWithN(const char* p, const size_t nLength) { 425 if (0 == nLength) { 426 return false; 427 } 428 const char* q = p + nLength; 429 while ('\0' == *q && --q >= p); 430 return (q >= p) && ('\n' == *q); 431 } 432 433 bool IniParser::stringEqual(const char* p, const char* q, int nChar/* = INT_MAX*/) const { 434 int n = 0; 435 if (p == q) { 436 return true; 437 } 438 while (*p && *q && *p == *q && n < nChar) { 439 ++p; 440 ++q; 441 ++n; 442 } 443 if ((n == nChar) || (*p == 0 && *q == 0)) { 444 return true; 445 } 446 return false; 447 } 448 449 bool IniParser::isSectionName(char* p, char* q) { 450 if (nullptr == p || nullptr == q) { 451 return false; 452 } 453 return '[' == *p && ']' == *q; 454 } 455 456 char* IniParser::splitKeyValue(char* p, char* q) { 457 char* pRetEqualSignPos = p; 458 while ('=' != *pRetEqualSignPos && ++pRetEqualSignPos < q); 459 return pRetEqualSignPos; 460 } 461 462 void IniParser::parseIniLine(char* szIniLine) { 463 char* p = szIniLine; 464 char* q = p + strlen(p); 465 this->trimRN0(p, q); 466 this->trim(p, q); 467 if (p < q) { 468 // 只有这种情况才需要处理.因为 p > q,肯定不需要处理,说明全都是空格.如果p = q也不需要处理,因为只有一个字符还需要处理什么? 469 *(q + 1) = '\0'; 470 if (this->isSectionName(p, q)) { 471 *q = '\0'; 472 ++p; 473 this->addSection(p); 474 } else { 475 char* szEqualSignPos = this->splitKeyValue(p, q); 476 if (szEqualSignPos > p && szEqualSignPos < q) { 477 *szEqualSignPos = '\0'; 478 ++szEqualSignPos; 479 this->addParameter(p, szEqualSignPos); 480 } 481 } 482 } 483 } 484 485 void IniParser::addSection(char* szSectionName) { 486 auto iter = m_mapSectionName.find(szSectionName); 487 if (m_mapSectionName.end() != iter) { 488 // 已存在 489 auto listiter = iter->second; 490 m_listSections.emplace_back(*listiter); 491 m_listSections.erase(listiter); 492 m_mapSectionName.erase(iter); 493 m_mapSectionName[szSectionName] = --m_listSections.end(); 494 return; 495 } 496 Section* pSection = new (std::nothrow) Section(szSectionName); 497 if (nullptr == pSection) { 498 return; 499 } 500 m_listSections.emplace_back(pSection); 501 m_mapSectionName[szSectionName] = --m_listSections.end(); 502 } 503 504 void IniParser::addParameter(char* szKey, char* szValue) { 505 if (m_listSections.empty()) { 506 return; 507 } 508 auto pSection = m_listSections.back(); 509 pSection->write(szKey, szValue); 510 } 511 512 }//namespace ns_ini
如果对该封装有改进或不当之处,欢迎指定、交流!
=== [Author: jacc.kim] & [e-mail: 175246359@qq.com] ===