1.类的作用
项目中,可能会需要用到各种各样的配置,比如数据库的host,root,pwd等配置。这些配置的值与代码本身没有关系,为了项目的灵活性和可移植性,可以在项目中写一个配置类
2.配置文件config.ini的格式
##代表注释后面的内容
#中括号内是配置的类型
[mysql]
#每一行代表一个配置
port= 3306
#允许出现空行
host =127.0.0.1
pwd=mdkdkd
#允许出现重复数据,但是后面的数据会覆盖前面的
pwd = 123456
user=root
db=test
#可以配置多组配置
[server]
port=10000
ip=127.0.0.1
id=1
3.写一个XConfig类,可以加载配置和获取配置
#ifndef X_CONFG
#define X_CONFG
#include <map>
class XConfig
{
private:
std::map<std::string, std::map<std::string, std::string>> m_config;
public:
bool load(std::string strPath);
std::string getConfigValue(std::string strGroupKey, std::string strKey);
};
#endif
4.实现XConfig类
#include "XConfig.h"
#include <iostream>
#include <fstream>
#include <vector>
bool XConfig::load(std::string strPath)
{
std::ifstream file;
file.open(strPath);
std::cout << "-------------------load config begin------------------" << std::endl;
std::string buf;
std::vector<std::string> vConfig;
while(getline(file, buf)) {
std::string value;
//将配置的元素拆分成字符串
for (auto c : buf) {
if (c == ' ') {
continue;
} else if (c == '#') {
break;
} else if (c == ']'){
value += c;
break;
} else if (c == '=') {
vConfig.push_back(value);
value = '=';
continue;
}
value += c;
}
if (value.size() > 0) {
vConfig.push_back(value);
}
}
int nIndex = 0;
std::string strGroupKey = "";
std::string strKey = "";
while (nIndex < vConfig.size()) {
auto& strConfig = vConfig[nIndex++];
//配置组名
if (strConfig[0] == '[') {
if (strConfig[strConfig.size() - 1] != ']') {
std::cout << "config error:" << strConfig << std::endl;
return false;
} else {
strGroupKey = strConfig.substr(1, strConfig.size() - 2);
}
continue;
}
//配置的值
if (strConfig[0] == '=') {
if (strGroupKey.size() == 0 || strKey.size() == 0) {
std::cout << "config error:" << strConfig << std::endl;
return false;
}
m_config[strGroupKey][strKey] = strConfig.substr(1, strConfig.size() - 1);
strKey = "";
continue;
}
//配置的名字
{
if (strGroupKey.size() == 0) {
std::cout << "config groupKey empty:" << strConfig << std::endl;
return false;
}
if (strKey.size() != 0) {
std::cout << "config strKey not empty:" << strConfig << std::endl;
return false;
}
strKey = strConfig;
}
}
file.close();
//打印加载的结果
for (auto itGroup = m_config.begin(); itGroup != m_config.end(); itGroup++) {
for (auto it = itGroup->second.begin(); it != itGroup->second.end(); it++) {
std::cout << "m_config[" << itGroup->first << "][" << it->first << "] = " << it->second << std::endl;
}
}
std::cout << "-------------------load config end------------------" << std::endl;
return true;
}
std::string XConfig::getConfigValue(std::string strGroupKey, std::string strKey)
{
auto itGroup = m_config.find(strGroupKey);
if (itGroup == m_config.end()) {
return "";
}
auto it = itGroup->second.find(strKey);
if (it == itGroup->second.end()) {
return "";
}
return it->second;
}
5.写一个main.cpp调用一下试试效果
#include <iostream>
#include "/usr/local/mysql/include/mysql.h"
#include "../proto/src/User.pb.h"
#include "XConfig.h"
MYSQL g_mysql;
int main(int argc, char** argv)
{
//加载配置
XConfig config;
if (!config.load(argv[1])) {
return -1;
}
//调用配置
std::string host = config.getConfigValue("mysql", "host");
std::string user = config.getConfigValue("mysql", "user");
std::string pwd = config.getConfigValue("mysql", "pwd");
std::string db = config.getConfigValue("mysql", "db");
if (!mysql_init(&g_mysql)) {
std::cout << "mysql_init err" << std::endl;
return -1;
}
if (!mysql_real_connect(&g_mysql, host.c_str(), user.c_str(), pwd.c_str(), db.c_str(), 0, NULL, CLIENT_MULTI_STATEMENTS)) {
std::cout << "mysql_real_connect err" << std::endl;
return -1;
}
//设置超时时间
int value = 2;
mysql_options(&g_mysql, MYSQL_OPT_READ_TIMEOUT, &value);
mysql_options(&g_mysql, MYSQL_SET_CHARSET_NAME, "utf8");
User user1;
user1.set_id(100);
user1.set_nickname("窑下村吴彦祖");
std::string str = "";
user1.SerializeToString(&str);
User user2;
user2.ParseFromString(str);
//insert
char sql[128];
snprintf(sql, sizeof(sql), "insert into user_data(user_id, user_data) value (%d, \'%s\');", user2.id(), str.c_str());
if (mysql_real_query(&g_mysql,sql,strlen(sql)) != 0) {
std::cout << "sql err! sql=" << sql << std::endl;
return false;
}
//select
char sql2[] = "select * from user_data;";
if (mysql_real_query(&g_mysql,sql2,strlen(sql2)) != 0) {
std::cout << "sql err! sql=" << sql2 << std::endl;
return false;
}
User user3;
auto res = mysql_store_result(&g_mysql);
auto num = mysql_num_rows(res);
for (int i = 0; i < num; i++) {
auto row = mysql_fetch_row(res);
std::cout << "user_id = " << row[0] << " user_data = " << row[1] << std::endl;
user3.ParseFromString(row[1]);
}
return 0;
}
6.修改run.sh,在./process后面加上配置文件
ulimit -c 10000
export LD_LIBRARY_PATH=/usr/local/lib/:/usr/local/mysql/lib:
./process config.ini
7.写配置文件config.ini
##代表注释后面的内容
#中括号内是配置的类型
[mysql]
#
port= 3306
host =127.0.0.1
pwd = 123456
user=root
db=test
[server]
port=10000
ip=127.0.0.1
id=1
8.看看执行的结果
9.小结
配置文件是程序不可少的一部分,一个好的配置加载类可以大大提升项目的稳定性,一般来说,特定的配置文件还需要一些复杂的校验逻辑,大家可以根据自己的项目需求,写特定的配置类。