【C++】手搓读写ini文件源码

发布于:2024-05-13 ⋅ 阅读:(144) ⋅ 点赞:(0)

【C++】手搓读写ini文件源码

思路

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

网站公告

今日签到

点亮在社区的每一天
去签到