在gitee上找到的一个很好用的ini文件解析器,纯C++代码,移植方便。
项目地址:https://gitee.com/sollyu/IniParser
稍微修改了下,去掉了Windows平台相关定义,改了下类名称。
头文件:
1 #ifndef INIPARSER_H 2 #define INIPARSER_H 3 4 5 #include <map> 6 #include <string> 7 #include <string.h> 8 9 class IniDoc 10 { 11 public: 12 struct IgnoreCaseLT 13 { 14 bool operator()(const std::string& lhs, const std::string& rhs) const 15 { 16 return strcasecmp(lhs.c_str(), rhs.c_str()) < 0; 17 } 18 }; 19 20 public: 21 typedef std::map<std::string, std::string, IgnoreCaseLT> KeyMap; 22 typedef std::map<std::string, KeyMap, IgnoreCaseLT> SectionMap; 23 typedef KeyMap::iterator KeyIterator; 24 typedef SectionMap::iterator SectionIterator; 25 26 public: 27 // 默认的构造函数和析构函数 28 IniDoc(); 29 ~IniDoc(); 30 31 // 构造函数 - 加载文件 32 IniDoc(const std::string& file_name); 33 34 // 加载一个ini文件, 如果之前的文件被修改, 那么之前的ini文件将会被保持。 35 bool load(const std::string& file_name); 36 37 // 从字符串中作为ini文件加载 38 bool loadString(const std::string& str); 39 40 // 保持到加载ini位置 41 bool save(); 42 43 // 另存为一个和加载路径不一样的文件中 44 bool saveAs(const std::string& file_name); 45 46 // 返回ini是否被修改, 或者他最后一次操作是保存 47 bool isModified() const { return m_modified; } 48 49 public: // high level member function. 50 51 // 下面的成员函数是从Section中获得一些值 52 long getInteger(const std::string& section, const std::string& key, long def_val); 53 float getFloat(const std::string& section, const std::string& key, float def_val); 54 long getStruct(const std::string& section, const std::string& key, void* buffer, long size); 55 long getString(const std::string& section, const std::string& key, const std::string& def_val, std::string& buffer); 56 const std::string getString(const std::string& section, const std::string& key, const std::string& def_val); 57 58 void setInteger(const std::string& section, const std::string& key, long value); 59 void setFloat(const std::string& section, const std::string& key, float value); 60 void setStruct(const std::string& section, const std::string& key, const void* buffer, long size); 61 void setString(const std::string& section, const std::string& key, const std::string& value); 62 63 public: 64 bool delSection( const std::string& section ); 65 bool delKey( const std::string& section, const std::string& key ); 66 67 public: 68 // 返回一个section的map键值对 69 const KeyMap& getSection(const std::string& section) const; 70 71 // 返回整个ini的Sections 72 const SectionMap& getIni() const { return m_map; } 73 74 private: 75 void saveBeforeLoad(); 76 const char* key_value(const std::string& section, const std::string& key); 77 78 private: 79 // 禁止复制构造函数和赋值操作符。 80 IniDoc(const IniDoc& copy); 81 IniDoc& operator=(const IniDoc& rhs); 82 83 private: 84 static const KeyMap ms_emptySection; 85 static const char left_tag ; 86 static const char right_tag ; 87 static const char equal ; 88 static const char cr ; 89 static const char new_line ; 90 static const char* empty_str ; 91 static const int BUFFER_LEN ; 92 93 SectionMap m_map; 94 std::string m_file_name; 95 bool m_modified; 96 }; 97 98 #endif // INIPARSER_H
源文件:
1 #include "IniDoc.h" 2 3 #include <fstream> 4 #include <strstream> 5 6 using namespace std; 7 8 const char IniDoc::left_tag = '[' ; 9 const char IniDoc::right_tag = ']' ; 10 const char IniDoc::equal = '=' ; 11 const char IniDoc::cr = ' '; 12 const char IniDoc::new_line = ' '; 13 const char* IniDoc::empty_str = "" ; 14 const int IniDoc::BUFFER_LEN = 255 ; 15 16 const IniDoc::KeyMap IniDoc::ms_emptySection; 17 18 IniDoc::IniDoc() : m_modified(false) 19 { 20 21 } 22 23 IniDoc::IniDoc(const std::string& file_name) : m_modified(false) 24 { 25 load(file_name); 26 } 27 28 IniDoc::~IniDoc() 29 { 30 if(m_modified) 31 save(); 32 } 33 34 void IniDoc::saveBeforeLoad() 35 { 36 if(m_modified) 37 save(); 38 39 m_file_name.resize(0); 40 41 m_map.clear(); 42 43 m_modified = false; 44 } 45 46 const char* IniDoc::key_value(const std::string& section, const std::string& key) 47 { 48 SectionIterator itSection = m_map.find(section); 49 if(m_map.end() != itSection) 50 { 51 KeyIterator itKey = itSection->second.find(key); 52 if(itKey != itSection->second.end()) 53 return itKey->second.c_str(); 54 } 55 56 return 0; 57 } 58 59 bool IniDoc::load(const std::string& file_name) 60 { 61 saveBeforeLoad(); 62 63 ifstream file(file_name); 64 if(!file) 65 return false; 66 67 file.seekg(0, ios::end); 68 long len = file.tellg(); 69 if(len < 0) 70 return false; 71 72 73 char* buffer = new char[len + 1]; 74 if(0 == buffer) 75 return false; 76 77 78 file.seekg(0, ios::beg); 79 file.read(buffer, len); 80 81 buffer[len = file.gcount()] = 0; 82 83 loadString(buffer); 84 m_file_name = file_name; 85 86 delete[] buffer; 87 88 return true; 89 } 90 91 bool IniDoc::loadString(const std::string& str) 92 { 93 saveBeforeLoad(); 94 95 unsigned long length = str.size(); 96 97 if (str.size() == 0) 98 return false; 99 100 enum status 101 { 102 after_left_tag, 103 after_section_name, 104 after_section_name_ws, 105 after_key_name, 106 after_key_name_ws, 107 after_equal, 108 start 109 }; 110 111 string section; // 当前 section. 112 string key; // 当前 key. 113 status sta = start; // 解析状态. 114 const char* p = str.c_str(); // 当前解析字符串的位置. 115 const char* beg = p; // 当前元素的开始. 116 const char* last_ws = p; // 最后一个空格字符. 117 118 for(; length; ++p, --length) 119 { 120 if(new_line == *p) 121 { 122 if(after_equal == sta) 123 { 124 if(cr == *(p - 1)) 125 --p; 126 127 m_map[section][key] = string(beg, p - beg); 128 129 if(cr == *p) 130 ++p; 131 } 132 sta = start; 133 } 134 else 135 { 136 switch(sta) 137 { 138 case after_left_tag: 139 if(right_tag == *p) 140 { 141 sta = start; 142 section = empty_str; // empty section name. 143 } 144 else if(!isspace((unsigned char)*p)) 145 { 146 sta = after_section_name; 147 beg = p; 148 } 149 break; 150 case after_section_name: 151 if(right_tag == *p) 152 { 153 sta = start; 154 section = string(beg, p - beg); 155 } 156 else if(isspace((unsigned char)*p)) 157 { 158 sta = after_section_name_ws; 159 last_ws = p; 160 } 161 break; 162 case after_section_name_ws: 163 if(right_tag == *p) 164 { 165 sta = start; 166 section = string(beg, last_ws - beg); 167 } 168 else if(!isspace((unsigned char)*p)) 169 { 170 sta = after_section_name; 171 } 172 break; 173 case after_key_name: 174 if(equal == *p) 175 { 176 sta = after_equal; 177 key = string(beg, p - beg); 178 beg = p + 1; 179 } 180 else if(isspace((unsigned char)*p)) 181 { 182 sta = after_key_name_ws; 183 last_ws = p; 184 } 185 break; 186 case after_key_name_ws: 187 if(equal == *p) 188 { 189 sta = after_equal; 190 key = string(beg, last_ws - beg); 191 beg = p + 1; 192 } 193 else if(!isspace((unsigned char)*p)) 194 { 195 sta = after_key_name; 196 } 197 break; 198 case start: 199 if(left_tag == *p) 200 { 201 sta = after_left_tag; 202 } 203 else if(equal == *p) 204 { 205 key = empty_str; // an empty key. 206 sta = after_equal; 207 beg = p + 1; 208 } 209 else if(!isspace((unsigned char)*p)) 210 { 211 sta = after_key_name; 212 beg = p; 213 } 214 break; 215 } 216 } 217 } 218 219 if(after_equal == sta) 220 m_map[section][key] = string(beg, p - beg); 221 222 return true; 223 } 224 225 bool IniDoc::save() 226 { 227 if(0==m_file_name.c_str() || 0==m_file_name[0]) 228 return false; // file name invalid 229 230 ofstream file(m_file_name.c_str()); 231 if(!file) 232 return false; 233 234 for(SectionMap::iterator itApp=m_map.begin(); itApp!=m_map.end(); ++itApp) 235 { 236 file << left_tag << itApp->first << right_tag << endl; 237 238 for(KeyMap::iterator itKey=itApp->second.begin(); itKey!=itApp->second.end(); ++itKey) 239 file << itKey->first << equal << itKey->second << endl; 240 241 file << endl; 242 } 243 m_modified = false; 244 245 return true; 246 } 247 248 bool IniDoc::saveAs(const std::string& file_name) 249 { 250 string old_file_name = m_file_name; 251 m_file_name = file_name; 252 253 if(save()) 254 return true; 255 256 m_file_name = old_file_name; 257 return false; 258 } 259 260 long IniDoc::getInteger(const std::string& section, const std::string& key, long def_val) 261 { 262 istrstream(key_value(section, key)) >> def_val; 263 return def_val; 264 } 265 266 float IniDoc::getFloat(const std::string& section, const std::string& key, float def_val) 267 { 268 istrstream(key_value(section, key)) >> def_val; 269 return def_val; 270 } 271 272 long IniDoc::getStruct(const std::string& section, const std::string& key_, void* buffer, long size) 273 { 274 std::string key = key_value(section, key_); 275 276 if (key.size() == 0) 277 return 0; 278 279 const char* p = key.c_str(); 280 char* dst = (char*)buffer; 281 long read_len = 0; 282 char value; 283 284 while(*p && read_len<size) 285 { 286 switch(*p) 287 { 288 case '0': case '1': case '2': case '3': case '4': 289 case '5': case '6': case '7': case '8': case '9': 290 value = *p - '0'; 291 break; 292 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': 293 value = *p - 'a' + 10; 294 break; 295 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': 296 value = *p - 'A' + 10; 297 break; 298 default: 299 return read_len; 300 } 301 302 303 if(0 == (p - key.c_str())%2) 304 *(dst + read_len) = value << 4; 305 else 306 *(dst + read_len) = (*(dst + read_len) & 0xf0) + value; 307 308 309 if(0 == (++p - key.c_str())%2) 310 ++read_len; 311 } 312 313 return read_len; 314 } 315 316 long IniDoc::getString(const std::string& section, const std::string& key_, const std::string& def_val, std::string& dst_str) 317 { 318 std::string key = key_value(section, key_); 319 dst_str = key.length() ? key : def_val; 320 return dst_str.length(); 321 } 322 323 const std::string IniDoc::getString(const std::string& section, const std::string& key_, const std::string& def_val) 324 { 325 std::string key = key_value(section, key_); 326 if(key.length() == 0) 327 key = def_val; 328 329 return key; 330 } 331 332 void IniDoc::setInteger(const std::string& section, const std::string& key, long value) 333 { 334 char buffer[BUFFER_LEN + 1]; 335 ostrstream ostr(buffer, BUFFER_LEN); 336 ostr << value; 337 buffer[ostr.pcount()] = 0; 338 setString(section, key, buffer); 339 } 340 341 void IniDoc::setFloat(const std::string& section, const std::string& key, float value) 342 { 343 char buffer[BUFFER_LEN + 1]; 344 ostrstream ostr(buffer, BUFFER_LEN); 345 ostr << value; 346 buffer[ostr.pcount()] = 0; 347 setString(section, key, buffer); 348 } 349 350 inline char bin2hex(char bin) 351 { 352 return bin<10 ? bin+'0' : bin-10+'A'; 353 } 354 355 void IniDoc::setStruct(const std::string& section, const std::string& key, const void* buffer, long size) 356 { 357 char* dst = new char[size*2 + 1]; 358 if(dst) 359 { 360 const char* src = (const char*)buffer; 361 long i=0; 362 for(i=0; i<size; ++i) 363 { 364 dst[i << 1] = bin2hex((src[i] >> 4) & 0x0f ); 365 dst[(i << 1) + 1] = bin2hex(src[i] & 0x0f); 366 } 367 368 dst[i << 1] = 0; 369 setString(section, key, dst); 370 371 delete[] dst; 372 } 373 } 374 375 void IniDoc::setString(const std::string& section, const std::string& key, const std::string& value) 376 { 377 m_map[section][key] = value; 378 m_modified = true; 379 } 380 381 bool IniDoc::delSection( const std::string& section ) 382 { 383 SectionIterator itSection = m_map.find(section); 384 if(m_map.end() != itSection) 385 { 386 m_map.erase(itSection); 387 return true; 388 } 389 return false; 390 } 391 392 bool IniDoc::delKey( const std::string& section, const std::string& key ) 393 { 394 SectionIterator itSection = m_map.find(section); 395 if(m_map.end() != itSection) 396 { 397 KeyIterator itKey = itSection->second.find(key); 398 if(itKey != itSection->second.end()) 399 { 400 itSection->second.erase(itKey); 401 return true; 402 } 403 } 404 return false; 405 } 406 407 const IniDoc::KeyMap& IniDoc::getSection(const std::string& section) const 408 { 409 SectionMap::const_iterator itApp = m_map.find(section); 410 return m_map.end()==itApp ? ms_emptySection : itApp->second; 411 }