思路
ini文件是一种系统配置文件,它有特定的格式组成。通常做法,我们读取ini文件并按照ini格式进行解析即可。在c++语言中,提供了模板类的功能,所以我们可以提供一个更通用的模板类来解析ini文件。c++中和键值对最贴切的就是STL中的map了。所以我使用map作为properties的实际内存存储,同时为了方便使用,另外多一个set类型的字段记录所有的key。大致流程为:
1、逐行扫描文件内容;
2、过滤注释(#后面的为注释);
3、根据等号切割key和value;
4、保存section,key和value到文件中;
需求:
1、当key没有值时:可以设定个默认值
2、读取文件时只有KEY没哟默认值会报错,添加一个默认值给该KEY
3、修改KEY的值时并保存到文件中,形成固定格式
ini.h
/**
******************************************************************************
* @file : ini.h
* @author : CircleDBA
* @mail : weiyuanquan@kingbase.com.cn
* @blog : circle-dba.blog.csdn.net
* @date : 24-5-8
******************************************************************************
*/
#ifndef KINGBASEMANAGERTOOLS_INI_H
#define KINGBASEMANAGERTOOLS_INI_H
#include <iostream>
#include <fstream>
#include <sstream>
#include <map>
#include <string>
#include <set>
#include <filesystem>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/filesystem.hpp>
using namespace std;
namespace Circle {
class ini {
protected:
string config_path;
set<string>* keys = nullptr;
map<string, string>* props = nullptr;
void trim(string& s);
vector<string> split(const string& str, char pattern);
private:
public:
ini();
virtual ~ini();
void file(boost::filesystem::path path);
bool is_exists();
bool load(std::string defaultValue);
bool load(){return load("None");};
set<string>* getKeys() const;
map<std::string, string> *const getProps() const;
string getValue(const string& key,const string& defaultValue);
string setValue(const string& key,const string& Value);
bool save();
};
} // Circle
#endif //KINGBASEMANAGERTOOLS_INI_H
ini.cpp
/**
******************************************************************************
* @file : ini.cpp
* @author : CircleDBA
* @mail : weiyuanquan@kingbase.com.cn
* @blog : circle-dba.blog.csdn.net
* @date : 24-5-8
******************************************************************************
*/
#include "ini.h"
namespace fs = boost::filesystem;
namespace Circle {
Circle::ini::ini() {
this->props = new map<string, string>;
this->keys = new set<string>();
}
Circle::ini::~ini() {
delete props;
delete keys;
}
void Circle::ini::file(boost::filesystem::path path){
this->config_path = path.string();
}
bool Circle::ini::is_exists(){
return fs::exists(this->config_path);
}
void Circle::ini::trim(string& s)
{
if (!s.empty())
{
s.erase(0, s.find_first_not_of(" "));
s.erase(s.find_last_not_of(" ") + 1);
}
}
vector<string> Circle::ini::split(const string& str, char pattern)
{
vector<string> res;
stringstream input(str);
string temp;
while (getline(input, temp, pattern))
{
res.push_back(temp);
}
return res;
}
bool Circle::ini::load(std::string defaultValue = "None"){
std::ifstream file(this->config_path);
std::string line, key, value, section;
while (getline(file, line)) {
trim(line);
//去空行
if (line.empty() || line == "\r" || line[0] == '#')
{
continue;
}
int s_startpos, s_endpos;
if (((s_startpos = line.find("[")) != -1) && ((s_endpos = line.find("]"))) != -1)
{
section = line.substr(s_startpos + 1, s_endpos - 1);
continue;
}
//处理等号后为空的配置
vector<string> res = split(line, '=');
if (res.size() < 2)
{
res[1] = defaultValue;
}
int t = res[1].find("#");
if (t != string::npos) {
res[1].erase(t);
}
for_each(res.begin(), res.end(), [=](string& s)mutable {
trim(s);
});
props->insert(make_pair(section+"."+res[0],res[1]));
keys->insert(section);
}
file.close();
return true;
}
set<string>* Circle::ini::getKeys() const {
return keys;
}
map<std::string, string> *const Circle::ini::getProps() const {
return this->props;
}
string Circle::ini::getValue(const string& key,const string& defaultValue) {
if (props->find(key) == props->end())
{
return defaultValue;
}
string value = this->props->at(key);
return value;
}
string Circle::ini::setValue(const string& key,const string& Value) {
if (props->find(key) == props->end())
{
this->props->insert(make_pair(key, Value));
}else{
props->at(key) = Value;
}
return this->props->at(key);
}
bool Circle::ini::save(){
std::ofstream outFile(this->config_path);
set<string>* keysMap = getKeys();
for (std::set<string>::const_iterator it = keysMap->begin(); it != keysMap->end(); ++it) {
outFile << "[" << *it << "]" << std::endl;
for (const auto &pair: *props) {
vector<string> res = split(pair.first,'.');
if(res[0] == *it){
outFile << res[1] << " = " << pair.second << std::endl;
}
};
}
return true;
}
} // Circle
config.conf
[group1]
IP = 192.168.30.1
name = group1
port = 7000
[group2]
IP = 192.168.1.101
name = group2
port = 7002
mian.cpp
/**
******************************************************************************
* @file : Application.h
* @author : CircleDBA
* @mail : weiyuanquan@kingbase.com.cn
* @blog : circle-dba.blog.csdn.net
* @date : 24-5-6
******************************************************************************
*/
#ifndef KINGBASEMANAGERTOOLS_APPLICATION_H
#define KINGBASEMANAGERTOOLS_APPLICATION_H
#include <iostream>
#include <boost/filesystem.hpp>
#include "src/path/path.h"
#include "src/config/ini.h"
namespace Circle {
class Application {
protected:
private:
public:
boost::filesystem::path RootPath,ConfigPath,DefaultConfigPath;
Circle::path* Path;
Application() {
RootPath = Path->ApplictionPath();
ConfigPath = RootPath / "config";
DefaultConfigPath = RootPath / "include" / "Application" / "config";
boost::filesystem::path config = DefaultConfigPath / "config.conf";
std::cout << "--------------------------------> start" << std::endl;
Circle::ini ini;
ini.file(config);
if(ini.is_exists()){
ini.load();
std::cout << ini.getValue("group1.IP","192.168.30.1") << std::endl;
std::cout << ini.setValue("group1.IP","192.168.30.1") << std::endl;
ini.save();
std::cout << "-------------------------------->for start" << std::endl;
map<string, string>* dataMap = ini.getProps();
for (const auto &pair : *dataMap) {
std::cout << pair.first << "=>" << pair.second <<std::endl;
};
}
std::cout << "--------------------------------> end" << std::endl;
}
};
} // Application
#endif //KINGBASEMANAGERTOOLS_APPLICATION_H