工程化项目配置【iniparser的安装与使用】

前言

对于很多程序中要用的参数如果是可变的,那么最好的处理方式就是通过main函数参数传递【就是我们经常见到的int main (int argc,char *argv[]){…}中的argc以及argv】,或者从别的地方去获取,这其中之一就是配置文件,但是在一个成熟和架构完善的系统,一般都会做到自动配置,自动部署,所以有的系统里会有一个单独的配置服务存在,每个其它的服务的配置信息从配置中心服务获取,然后运维人员通过操作界面把配置信息下发给配置中心服务,其余服务从配置中心获取变更信息。
几乎每一个大型互联网项目都会涉及到项目配置,如mysql 的配置文件:
在这里插入图片描述

自己写的一个ini配置文件👇:

[database]
ip       = 127.0.0.1 ;
port     = 3306 ;
user     = root ;
pwd      = 123456 ;
db       = mybike;

[server]
port     = 9090;

我们先来看下ini的配置文件,例如我们的配置文件如下,[database]就是我们的俗称的区段,ipport就是字段,127.0.0.1和3306就是字段的值。
那么要如何对ini文件进行解析呢,首先想到的是不是使用文件流将文件中的内存读取出来,然后通过hash来进行key-value的存储,但是这样就会麻烦了,我们可以用别人写好的开源库iniparser来解析配置文件iniparser在github上的地址


iniparser的安装

git clone https://github.com/ndevilla/iniparser
cd iniparser
make

make 以后会生成libiniparser.so.1以及libiniparser.a,而src目录下有dictionary.h以及iniparser.h
在这里插入图片描述
在写工程级的代码时,一般会有testsrc文件夹、confthird文件夹,其中third文件夹就是用来存放第三方头文件源文件以及库
在这里插入图片描述
当我们make以后生成库以及头文件,将库、头文件以及cpp文件放入到自己项目的third文件夹中
在这里插入图片描述


ini文件通过iniparser进行解析

先来展示下我的ini文件
shared_bike.ini

[database]
ip       = 127.0.0.1 ;
port     = 3306 ;
user     = root ;
pwd      = 123456 ;
db       = mybike;

[server]
port     = 9090;

代码展示

configdef.h
将后续通过iniparser解析出来的数据保存到st_env_config结构中

#ifndef SHBK_COMMON_CONFIGDEF_H
#define SHBK_COMMON_CONFIGDEF_H
#include <string>
typedef struct st_env_config
{
   //数据库的配置
   std::string db_ip;
   unsigned short db_port;
   std::string db_user;
   std::string db_pwd;
   std::string db_name;

   //服务的配置
   unsigned short svr_port;

   st_env_config()
   {
   };

   st_env_config(const std::string& db_ip, unsigned int db_port, const std::string& db_user, \
                 const std::string& db_pwd, const std::string& db_name, unsigned short svr_port)
   {
       this->db_ip    = db_ip;
       this->db_port  = db_port;
       this->db_user  = db_user;
       this->db_pwd   = db_pwd;
       this->db_name  = db_name;
       this->svr_port = svr_port;
   };
    st_env_config& operator =(const st_env_config& config)
   {
       if (this != &config)
       {
		   this->db_ip    = config.db_ip;
		   this->db_port  = config.db_port;
		   this->db_user  = config.db_user;
		   this->db_pwd	  = config.db_pwd;
		   this->db_name  = config.db_name;
		   this->svr_port = config.svr_port;

        }
        return *this;
    }
}_st_env_config;

#endif//SHBK_COMMON_CONFIGDEF_H

iniconfig.h
将解析操作分装成一个类,将解析出来的结果保存到st_env_config结构中

#ifndef SHBK_COMMON_INICONFIG_H
#define SHBK_COMMON_INICONFIG_H
#include <string>
#include <stddef.h>
#include "configdef.h"
class Iniconfig
{
    public:
        Iniconfig();
        ~Iniconfig();
        bool loadFile(const std::string&path);
        const st_env_config& getconfig();
    private:
        //用来存储配置文件读取出来的具体参数
        st_env_config _config;
        //是否已经加载过了
        bool isLoaded;
};

#endif

iniconfig.cpp

#include "iniconfig.h"
//一会儿使用cmake将third文件夹包含进来
#include <iniparser/iniparser.h>
#include <iniparser/dictionary.h>
Iniconfig::Iniconfig():isLoaded(false)
{

}
Iniconfig::~Iniconfig()
{

}

bool Iniconfig::loadFile(const std::string& path)
{
	//需要定义一个字典ini指针
    dictionary*   ini = NULL;
	//使用iniparser_load方法对ini文件进行解析,结果用字典来存
    ini = iniparser_load(path.c_str());
    if (ini==NULL)
    {
        printf("cannot parse file: %s\n", path.c_str());
        return false;
    }
    //区段:字段,如果这个字段不存在那么就是默认值127.0.0.1
    const char* ip    = iniparser_getstring(ini, "database:ip", "127.0.0.1");
    int   port  = iniparser_getint(ini, "database:port", 3306);
    const char* user  = iniparser_getstring(ini, "database:user", "root");
    const char* pwd   = iniparser_getstring(ini, "database:pwd", "123456");
    const char* db    = iniparser_getstring(ini, "database:db", "bike");
    int   sport = iniparser_getint(ini, "server:port", 9090);

    //构造st_env_config结构体
    _config = st_env_config(std::string(ip), port, std::string(user), \
        std::string(pwd), std::string(db), sport);

    //释放字典
    iniparser_freedict(ini);

    isLoaded = true;

    return true;
}

const st_env_config&  Iniconfig::getconfig()
{
    return _config;
}

main.cpp

#include "iniconfig.h"
#include "configdef.h"

//后续执行命令:xx.exe ./conf/shared_bike.ini
int main(int argc,char** argv)
{
    if(argc!=2)
    {
        printf("Please input shbk <config file path>!\n");
        return -1;
    }

    Iniconfig config;
    if(!config.loadFile(std::string(argv[1])))
    {
        printf("load %s is failed.\n",argv[1]);
        return -2;
    }
    
    st_env_config conf_args = config.getconfig();
    printf("[database] ip:%s port:%d user:%s\n",conf_args.db_ip.c_str(),conf_args.db_port,conf_args.db_user);

    return 0;
}

iniparser解析数据的流程

1、创建字典

//定义一个字典ini指针
dictionary*   ini = NULL;

2、加载数据

//使用iniparser_load方法对ini文件进行解析,结果用字典来存
ini = iniparser_load(path.c_str());

3、读取字典中的数据(可以将字典中的数据转存到一个类中进行保存)

//区段:字段,如果这个字段不存在那么就是默认值127.0.0.1
const char* ip    = iniparser_getstring(ini, "database:ip", "127.0.0.1");
int   port  = iniparser_getint(ini, "database:port", 3306);
const char* user  = iniparser_getstring(ini, "database:user", "root");
const char* pwd   = iniparser_getstring(ini, "database:pwd", "123456");
const char* db    = iniparser_getstring(ini, "database:db", "bike");
int   sport = iniparser_getint(ini, "server:port", 9090);

什么是区段和字段呢?👇
在这里插入图片描述


cmake设计

要使用cmake来对这几个文件进行编译链接,所以来来看看俺的目录结构吧:
在这里插入图片描述

可以看到有两个CMakeLists.txt,里层的CMakeLists.txt是为了生成一个libcommon.a的库,在这个库中实现了一个类Iniconfig,它使用了iniparser对ini文件进行解析,并将结果存入到一个st_env_config类中,而外层CMakeLists.txt就是为了执行main函数,将libcommon.a进行使用,最终看到解析ini文件之后的结果【很多注释都在cmake的语句中了,如果对于cmake不熟悉的同学可以仔细看看下面的注释】

和main函数同级的外层CMakeList.txt

CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT(myBike)

# 包含头文件目录
INCLUDE_DIRECTORIES(./common)
INCLUDE_DIRECTORIES(../third/include)

# 包含库目录
LINK_DIRECTORIES(../third/lib/iniparser)
LINK_DIRECTORIES(./common)

# 用来显式的定义变量
# 设置编译选项
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic -Wall -m64 -pipe -std=c++0x -lrt -Wno-reorder -Wdeprecated-declarations")

# 收集指定目录下的文件名列表保存到变量中
aux_source_directory(. SOURCE_FILES)

ADD_EXECUTABLE(myBike ${SOURCE_FILES})

# 将具体的库链接上去
TARGET_LINK_LIBRARIES(myBike common)
TARGET_LINK_LIBRARIES(myBike iniparser)

# 执行common文件夹下的CMakeLists.txt(这个操作就是生成libcommon.a)
ADD_SUBDIRECTORy(common)

common文件夹中的里层CMakeList.txt

CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

# 收集指定目录下的文件名列表保存到变量中
aux_source_directory(. SOURCE_COMMON_FILES)
# 将这些个文件构建成一个库
ADD_LIBRARY(common ${SOURCE_COMMON_FILES})

# 用来显式的定义变量
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic -Wall -m64 -pipe -std=c++0x -lrt -Wno-reorder -Wdeprecated-declarations")

# 将指定目录添加到编译器的头文件搜索路径下
INCLUDE_DIRECTORIES(../../third/include)
# 将指定目录添加到需要链接的库文件目录之下
LINK_DIRECTORIES(../../third/lib/iniparser)

# 将iniparser的库链接到common上
TARGET_LINK_LIBRARIES(common iniparser)
# TARGET_LINK_LIBRARIES(common dl)

运行结果:
在这里插入图片描述


结语

在本文中,我们介绍了如何使用iniparser库在Linux中解析INI文件,并使用CMake来构建我们的项目。我们首先简单展示了INI文件的格式,然后演示了如何使用iniparser库来读取INI文件中的配置信息。接下来,我们学习了如何使用CMake来配置我们的项目,并编写了CMakeLists.txt文件。最后,我们演示了如何使用CMake来构建我们的项目,并成功地解析了INI文件中的配置信息。

通过本文,我希望读者能够了解如何在Linux中使用iniparser库来解析INI文件,并学习如何使用CMake来构建C++项目。在实际工作中,配置文件是非常常见的,而INI文件作为其中的一种格式也是非常重要的。因此,掌握使用iniparser库来解析INI文件的方法,将有助于我们更加高效地处理配置文件。此外,使用CMake来构建C++项目也是一个非常重要的技能,它可以帮助我们更好地管理和组织我们的代码。

感谢您的阅读,希望本文对您有所帮助!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值