支持无段名的配置项
#ifndef __CONFIGFILEINI_H_
#define __CONFIGFILEINI_H_
#include <unordered_map>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <memory>
#include <mutex>
#define CONF_DEFAULT_VALUE "NULL"
using namespace std;
//支持空域名
static string & trim_copy(string & s)
{
if (s.empty())
{
return s;
}
s.erase(0, s.find_first_not_of(" "));
s.erase(s.find_last_not_of(" ") + 1);
return s;
}
class ConfigSection {
private:
string m_sect_name;
unordered_map<string, string> m_datas;
public:
ConfigSection(const string & name = "")
:m_sect_name(name)
{
m_datas.clear();
}
public:
void AddContext(const string& context)
{
size_t posEqual = context.find('=');
if (posEqual == string::npos)
return;
string key = context.substr(0, posEqual); //读取从0位到“=”返回位的内容。
key = trim_copy(key); //boost库去掉前后的空格
string value = context.substr(posEqual + 1);//读取从“=”返回位下一位到最后的内容
value = trim_copy(value);
auto it = m_datas.find(key);
if (it == m_datas.end())
{
m_datas.insert(make_pair(key, value));
}
else
{
m_datas[key] = value;
}
}
void AddContext(const string& key, const string& value)
{
auto it = m_datas.find(key);
if (it == m_datas.end())
{
m_datas.insert(make_pair(key, value));
}
else
{
m_datas[key] = value;
}
}
void RemoveContext(const string & key)
{
auto it = m_datas.find(key);
if (it != m_datas.end())
{
m_datas.erase(it);
}
}
bool GetContext(const string & key, string & value)
{
auto it = m_datas.find(key);
if (it != m_datas.end())
{
value = it->second;
return true;
}
return false;
}
void Write2File(ofstream& stream)
{
if (!m_sect_name.empty())
{
stream << "[" << m_sect_name << "]" << endl;
}
for (auto &e : m_datas)
{
stream << e.first << " = " << e.second << endl;
}
}
};
class ConfigFile {
private:
string m_file_name;
std::mutex m_mutex;
unordered_map<string, shared_ptr<ConfigSection>> m_sections;
ConfigSection notitle_section;
private:
void read_file(const string & file_name)
{
ifstream file(file_name.c_str());
string line;
std::shared_ptr<ConfigSection> temp_section(0);
while (getline(file, line))
{
line = trim_copy(line);
if (line.empty())
continue;
if (line[0] == '#')
continue;
if (is_sect_head(line))
{
string sect_head = line.substr(1, line.size() - 2);
sect_head = trim_copy(sect_head);
temp_section = std::shared_ptr<ConfigSection>(new ConfigSection(sect_head));
m_sections.insert(make_pair(sect_head, temp_section));
}
else
{
if (temp_section == NULL)
{
notitle_section.AddContext(line);
}
else
{
temp_section->AddContext(line);
}
}
}
file.close();
}
inline bool is_sect_head(const string& context)
{
return (context.front() == '[' && context.back() == "]")
}
public:
ConfigFile(string fileName)
:m_file_name(fileName)
, notitle_section("")
{
read_file(fileName);
}
void Save2File(const string & fileName)
{
std::unique_lock<std::mutex> lk(m_mutex);
ofstream stream;
stream.open(fileName.c_str(), ios::out | ios::trunc);
notitle_section.Write2File(stream);
for (auto &e : m_sections)
{
e.second->Write2File(stream);
}
stream.close();
}
void Save2File() { Save2File(m_file_name); }
string GetValue(string const& key, string const& sect_name = "", string const & default_value = CONF_DEFAULT_VALUE)
{
std::unique_lock<std::mutex> lk(m_mutex);
string value;
if (sect_name.empty())
{
if (notitle_section.GetContext(key, value))
{
return value;
}
return default_value;
}
auto it = m_sections.find(sect_name);
if (it == m_sections.end())
{
return default_value;
}
if (it->second->GetContext(key, value))
{
return value;
}
return default_value;
}
void AddSection(const string& section)
{
unique_lock<std::mutex> lk(m_mutex);
auto it = m_sections.find(section);
if (it == m_sections.end())
{
shared_ptr<ConfigSection> s = make_shared<ConfigSection>(section);
m_sections.insert(make_pair(section, s));
}
}
void RemoveSection(const string & section)
{
unique_lock<std::mutex> lk(m_mutex);
auto it = m_sections.find(section);
if (it != m_sections.end())
{
m_sections.erase(it);
}
}
void AddContext(const string & key, const string & value, const string & section)
{
unique_lock<std::mutex> lk(m_mutex);
if (section.empty())
{
notitle_section.AddContext(key, value);
return;
}
shared_ptr<ConfigSection> temp_section;
auto it = m_sections.find(section);
if (it == m_sections.end())
{
shared_ptr<ConfigSection> s = make_shared<ConfigSection>(section);
m_sections.insert(make_pair(section, s));
temp_section = s;
}
else
{
temp_section = it->second;
}
temp_section->AddContext(key, value);
}
void RemoveContext(const string & key, const string & section)
{
unique_lock<std::mutex> lk(m_mutex);
if (section.empty())
{
notitle_section.RemoveContext(key);
return;
}
auto it = m_sections.find(section);
if (it == m_sections.end())
{
return;
}
shared_ptr<ConfigSection> temp_section = it->second;
temp_section->RemoveContext(key);
}
};
#endif