使用std库解析INI配置文件,可以区分“;”间隔的注释,缺点是如果有修改配置值,会把注释顶掉。
头文件:
#ifndef INI_PARSER_HPP
#define INI_PARSER_HPP
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <cstdlib>
#include <map>
#include <string>
#include <mutex>
using namespace std;
class INIParser
{
private:
map<string, map<string, string>> _map_ini;
string & replace_all(string & str, const string & old_value, const string & new_value);
string & replace_all_distinct(string & str, const string & old_value, const string & new_value);
public:
~INIParser() { Clear(); }
size_t GetSize() const { return _map_ini.size(); }
string getStringFromFile(const string &file);
bool ReadINI(const string & fileName);
string GetString(const string & root, const string & key, const string & def = "") const;
int GetInt(const string & root, const string & key, int def = 0) const;
double GetDouble(const string & root, const string & key, double def = 0) const;
bool GetBool(const string & root, const string & key, bool def = false) const;
void SetValue(const string & root, const string & key, const string & value);
void SetString(const string & root, const string & key, const string & value);
void SetInt(const string & root, const string & key, int value);
void SetDouble(const string & root, const string & key, double value);
void SetBool(const string & root, const string & key, bool value);
bool WriteINI(const string & path);
void Clear() { _map_ini.clear(); }
void View();
};
#endif // INI_PARSER_HPP
cpp:
#include "ini_parser.hpp"
#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <stdio.h>
static void TrimString(string & str)
{
str.erase(0, str.find_first_not_of(' '));
str.erase(str.find_last_not_of(' ')+1);
}
string & INIParser::replace_all(string & str, const string & old_value, const string & new_value)
{
while (true)
{
string::size_type pos = 0;
pos = str.find(old_value);
if (pos == string::npos) break;
str.replace(pos, old_value.length(), new_value);
}
return str;
}
string & INIParser::replace_all_distinct(string & str, const string & old_value, const string & new_value)
{
for (size_t pos = 0; pos != string::npos; pos += new_value.length())
{
pos = str.find(old_value, pos);
if (pos == string::npos) break;
str.replace(pos, old_value.length(), new_value);
}
return str;
}
string INIParser::getStringFromFile(const string &file)
{
unsigned char* buffer = nullptr;
size_t size = 0;
size_t readsize;
// Read the file from hardware
FILE *fp = nullptr;
fopen_s(&fp,file.c_str(), "rt");
if (fp == nullptr)
{
return "";
}
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
buffer = (unsigned char*)malloc(sizeof(unsigned char) * (size + 1));
buffer[size] = '\0';
readsize = fread(buffer, sizeof(unsigned char), size, fp);
fclose(fp);
if (readsize < size)
{
buffer[readsize] = '\0';
}
string str((char*)buffer);
free(buffer);
return str;
}
bool INIParser::ReadINI(const string & fileName)
{
stringstream in_conf_file;
try
{
string content = getStringFromFile(fileName);
replace_all_distinct(content, "\r", "\n");
if (content.empty()) return false;
in_conf_file << content;
string str_line = "";
map<string, string> * kv_node = nullptr;
size_t left_pos;
size_t right_pos;
size_t equal_div_pos;
while (getline(in_conf_file, str_line))
{
if (str_line.empty()) continue;
if ((string::npos != (left_pos = str_line.find("["))) &&
(str_line.npos != (right_pos = str_line.find("]"))))
{
//配置头
string root = str_line.substr(left_pos + 1, right_pos - left_pos - 1);
TrimString(root);
if (!root.empty())
{
_map_ini[root] = map<string, string>{};
kv_node = &(_map_ini[root]);
}
}
else if (string::npos != (equal_div_pos = str_line.find("=")))
{
//配置项,需要注意;为注释
string key = str_line.substr(0, equal_div_pos);
size_t notePos = str_line.find(";");
string value;
if (string::npos != notePos)
{
value = str_line.substr(equal_div_pos + 1, notePos - equal_div_pos - 1);
}
else
{
value = str_line.substr(equal_div_pos + 1, str_line.size() - 1);
}
TrimString(key);
TrimString(value);
if (kv_node != nullptr && !key.empty())
{
(*kv_node)[key] = value;
}
}
}
return true;
}
catch (...)
{
return false;
}
}
void INIParser::View()
{
for (auto it = _map_ini.begin(); it != _map_ini.end(); ++it)
{
printf(it->first.c_str());
printf("\n");
for (auto vit = it->second.begin(); vit != it->second.end(); ++vit)
{
printf(vit->first.c_str());
printf(" = ");
printf(vit->second.c_str());
printf("\n");
}
}
}
string INIParser::GetString(const string & root, const string & key, const string & def) const
{
auto itr = _map_ini.find(root);
if (itr == _map_ini.end()) return "";
auto sub_itr = itr->second.find(key);
if (sub_itr == itr->second.end()) return "";
if (!(sub_itr->second).empty()) return sub_itr->second;
return def;
}
int INIParser::GetInt(const string & root, const string & key, int def) const
{
string str = GetString(root, key, "");
if (str.empty()) return def;
int res;
try
{
istringstream is(str);
is >> res;
}
catch(...)
{
res = def;
}
return res;
}
double INIParser::GetDouble(const string & root, const string & key, double def) const
{
string str = GetString(root, key, "");
if (str.empty()) return def;
double res;
try
{
istringstream is(str);
is >> res;
}
catch(...)
{
res = def;
}
return res;
}
bool INIParser::GetBool(const string & root, const string & key, bool def) const
{
string str = GetString(root, key, "");
if (str.empty()) return def;
if (str == "1") return true;
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
if (str == "true") return true;
return false;
}
bool INIParser::WriteINI(const string & path)
{
ofstream out_conf_file(path.c_str());
if (!out_conf_file) return false;
for (auto itr = _map_ini.begin(); itr != _map_ini.end(); ++itr)
{
out_conf_file << "[" << itr->first << "]" << endl;
for (map<string, string>::iterator sub_itr = itr->second.begin();
sub_itr != itr->second.end(); ++sub_itr)
{
out_conf_file << sub_itr->first << "=" << sub_itr->second << endl;
}
}
out_conf_file.close();
out_conf_file.clear();
return true;
}
void INIParser::SetValue(const string & root, const string & key, const string & value)
{
auto itr = _map_ini.find(root);
if (_map_ini.end() != itr)
{
map<string, string>::iterator it = itr->second.find(key);
if (it != itr->second.end())
{
it->second = value;
}
else
{
itr->second[key] = value;
}
}
else
{
map<string, string> m;
m[key] = value;
_map_ini[root] = std::move(m);
}
}
void INIParser::SetString(const string & root, const string & key, const string & value)
{
SetValue(root, key, value);
}
void INIParser::SetInt(const string & root, const string & key, int value)
{
char buf[32];
sprintf_s(buf, "%d", value);
SetValue(root, key, buf);
}
void INIParser::SetDouble(const string & root, const string & key, double value)
{
char buf[64];
sprintf_s(buf, "%lf", value);
SetValue(root, key, buf);
}
void INIParser::SetBool(const string & root, const string & key, bool value)
{
if (value) SetValue(root, key, "1");
else SetValue(root, key, "0");
}
测试:
int main()
{
string file = "F:\\VersionConfig.ini";
INIParser ini;
printf(ini.getStringFromFile(file).c_str());
printf("\n");
ini.ReadINI(file);
ini.View();
system("pause");
return 0;
}