Boost学习之读写ini文件

在程序开发中,配置文件扮演着很重要的角色,实现程序的灵活配置,方便不同环境下部署和使用,对于一些随着外界环境变化的参数,直接写入配置文件。本文将介绍boost总ini配置文件的读写。

初始化ini解析器

在程序开发中,文件读写是很重要的一个环节,同样,boost也提供了强大的文件读写功能,对于C++中经常使用的ini文件,boost直接提供了解析接口,使用者可以很方便的调用。

在boost中,解析ini文件的接口定义在如下文件中。

#include <boost/property_tree/ini_parser.hpp>

boost操作ini文件,是按照树形结构解析读取的,对应的树形结构解析接口位于如下头文件中。

#include <boost/property_tree/ptree.hpp>

初始化init文件的接口为 :read_ini,从boost源码可以看出,初始化流程如下:

  1. 打开文件流;
  2. 逐行读取文件,解析为property tree
  3. 将解析后的property tree返回给使用者;

后续的读、写、修改都需要基于当前的property tree,该接口的实现源码如下:

   /**
     * Read INI from a the given file and translate it to a property tree.
     * @note Clears existing contents of property tree.  In case of error the
     *       property tree unmodified.
     * @throw ini_parser_error In case of error deserializing the property tree.
     * @param filename Name of file from which to read in the property tree.
     * @param[out] pt The property tree to populate.
     * @param loc The locale to use when reading in the file contents.
     */
    template<class Ptree>
    void read_ini(const std::string &filename, 
                  Ptree &pt,
                  const std::locale &loc = std::locale())
    {
        std::basic_ifstream<typename Ptree::key_type::value_type>
            stream(filename.c_str());    //open file
        if (!stream)
            BOOST_PROPERTY_TREE_THROW(ini_parser_error(
                "cannot open file", filename, 0));
        stream.imbue(loc);
        try {
            read_ini(stream, pt);   //start parse ini file
        }
        catch (ini_parser_error &e) {
            BOOST_PROPERTY_TREE_THROW(ini_parser_error(
                e.message(), filename, e.line()));
        }
    }

 /**
     * Read INI from a the given stream and translate it to a property tree.
     * @note Clears existing contents of property tree. In case of error
     *       the property tree is not modified.
     * @throw ini_parser_error If a format violation is found.
     * @param stream Stream from which to read in the property tree.
     * @param[out] pt The property tree to populate.
     */
    template<class Ptree>
    void read_ini(std::basic_istream<
                    typename Ptree::key_type::value_type> &stream,
                  Ptree &pt)
    {
        typedef typename Ptree::key_type::value_type Ch;
        typedef std::basic_string<Ch> Str;
        const Ch semicolon = stream.widen(';');
        const Ch hash = stream.widen('#');
        const Ch lbracket = stream.widen('[');
        const Ch rbracket = stream.widen(']');

        Ptree local;
        unsigned long line_no = 0;
        Ptree *section = 0;
        Str line;

        // For all lines
        while (stream.good())
        {

            // Get line from stream
            ++line_no;
            std::getline(stream, line);
            if (!stream.good() && !stream.eof())
                BOOST_PROPERTY_TREE_THROW(ini_parser_error(
                    "read error", "", line_no));

            // If line is non-empty
            line = property_tree::detail::trim(line, stream.getloc());
            if (!line.empty())
            {
                // Comment, section or key?
                if (line[0] == semicolon || line[0] == hash)
                {
                    // Ignore comments
                }
                else if (line[0] == lbracket)
                {
                    // If the previous section was empty, drop it again.
                    if (section && section->empty())
                        local.pop_back();
                    typename Str::size_type end = line.find(rbracket);
                    if (end == Str::npos)
                        BOOST_PROPERTY_TREE_THROW(ini_parser_error(
                            "unmatched '['", "", line_no));
                    Str key = property_tree::detail::trim(
                        line.substr(1, end - 1), stream.getloc());
                    if (local.find(key) != local.not_found())
                        BOOST_PROPERTY_TREE_THROW(ini_parser_error(
                            "duplicate section name", "", line_no));
                    section = &local.push_back(
                        std::make_pair(key, Ptree()))->second;
                }
                else
                {
                    Ptree &container = section ? *section : local;
                    typename Str::size_type eqpos = line.find(Ch('='));
                    if (eqpos == Str::npos)
                        BOOST_PROPERTY_TREE_THROW(ini_parser_error(
                            "'=' character not found in line", "", line_no));
                    if (eqpos == 0)
                        BOOST_PROPERTY_TREE_THROW(ini_parser_error(
                            "key expected", "", line_no));
                    Str key = property_tree::detail::trim(
                        line.substr(0, eqpos), stream.getloc());
                    Str data = property_tree::detail::trim(
                        line.substr(eqpos + 1, Str::npos), stream.getloc());
                    if (container.find(key) != container.not_found())
                        BOOST_PROPERTY_TREE_THROW(ini_parser_error(
                            "duplicate key name", "", line_no));
                    container.push_back(std::make_pair(key, Ptree(data)));
                }
            }
        }
        // If the last section was empty, drop it again.
        if (section && section->empty())
            local.pop_back();

        // Swap local ptree with result ptree
        pt.swap(local);

    }

具体调用示例代码如下:

bool Init()
{
	// 调用boost 文件系统接口,先检查文件是否存在。
	if (!boost::filesystem::exists(this->strFileName))
	{
		cout << "file not exists!" << endl;
		return false;
	}
	
	// 调用read_ini接口,将ini文件内容读入 root_node树节点中。
	// root_node类型为:boost::property_tree::ptree
	boost::property_tree::ptree root_node;
	boost::property_tree::ini_parser::read_ini(this->strFileName, root_node);
	return true;
}
写入ini文件
使用ofstream写入

使用ofstream对象写入,直接使用了C++写文件方式,示例代码如下:

boost::filesystem::ofstream ostream("config.ini", std::ios_base::out);
		ostream << "[System] \n";
		ostream << "ip=127.0.0.1\n";
		ostream << "port=8080\n";
		ostream << "[sdk]\n";
		ostream << "path=C:\\log\n";
		
		ostream.close();

文件样式:
在这里插入图片描述

使用boost接口写入

使用boost提供的API写入文件,需要用到boost::property_tree::ptree结构的 put 方法。示例代码如下:


bool UpdateItem(string strRoot_child_name,string value)
{
	// put rootnode.childnode value
	boost::property_tree::ptree root_node
	// put第一个参数需要传入子节点和子节点下元素的名称,中间用.隔开,比如System.pwd
	this->root_node.put<string>(strRoot_child_name, value);
	write_ini("config.ini", root_node);
	return true;
}

调用示例

config.UpdateItem("System.ip", "192.168.10.12");
config.UpdateItem("System.pwd", "admin_123455");
config.UpdateItem("ThirdPart.age", "10");

文件显示结果:
在这里插入图片描述

读取ini文件

读取ini文件也非常简单,需要使用boost提供的 get 函数读取对应的字段值,示例代码如下:

int Get_int_value(string node_name, string child_name)
{
	boost::property_tree::ptree child_node;

	// return child node
	child_node = root_node.get_child(node_name);
	
	// get child value
	return child_node.get<int>(child_name);
}
修改ini文件

修改ini文件,同样需要用到boost库的put方法。前提是指定已经存在的节点和节点下面的字段名称。如果该字段存在,则修改,如果不存在,则新增。

bool UpdateItem(string strRoot_child_name, string value)
{
	// put rootnode.childnode value
	this->root_node.put<string>(strRoot_child_name, value);
	write_ini("config.ini", root_node);
	return true;
}

调用函数

config.UpdateItem("ThirdPart.age", "5555555555555");

修改结果:
在这里插入图片描述

以上是ini配置文件的创建、修改和新增操作,当然,按照模板,手动也可以增删改。每个人的使用习惯不同,可以按照各自习惯灵活使用。本文中测试代码,已经重新封装,直接链接即可使用,有需要可以参见博主的github仓库【最近刚刚开始玩git,后续所有代码将收录入仓库】,地址为:https://github.com/Marccp-code/boost,如果本文对你工作、学习等有帮助,请点赞支持我,若有错误或者bug,请随时联系博主修改更新,谢谢。

  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值