STL简洁 && c++读取cfg文件

时间:2023-02-11 14:32:15

  在c++工程中,往往需要修改一些变量来实现不同的功能效果,这是cfg文件的使用可以使得工程更加高效与便利,这篇文章介绍的就是c++读取cfg文件的相关内容,以便及时总结和日后回顾。

  STL即标准模板库,其包含了很多基本的数据结构和基本算法,实现了软件的高复用性,在标准中,STL包含13个头文件,包括<map>、<set>、<queue>等。

  所有的容器都具有一些成员函数,包括默认构造函数、复制构造函数、析构函数、empty(判断容器是否为空)、max_size(返回容器最大容量)、size(返回容器当前的数量)、swap(交换两个容器中的元素。且很多容器还具有begin、end、rbegin、rend、erase、clear等方法来迅速获取到其中的某一个元素。这里我们主要介绍map容器。

  map是关联容器,是映射类的模板,下面的例子是演示map的用法,如下:

#include <iostream>
#include <string>
#include <map>
using namespace std;
int main()
{
string name[] = {"wanye", "hedy", "jack"};
double salary[] = {, , };
map<string, double> sal;
map<string, double>::iterator p; // 建立映射遍历器
for (int i = ; i < ; i++) // 将name和salary映射到map中
sal.insert(make_pair(name[i],salary[i]));
sal["bob"] = ;
sal["mark"] = ;
for ( p = sal.begin(); p != sal.end(); p++)
cout << p->first << "\t" << p->second << endl;
cout << "输入需要查找人的姓名:" << endl;
string foo;
cin >> foo;
bool b = false;
for (p = sal.begin(); p != sal.end(); p++)
{
if (p->first == foo)
{
cout << p->second << endl;
b = true;
}
}
if (b == false)
{
cout << "不存在该员工!" << endl;
}
return ;
}

以上程序就是将员工姓名和工资存入map中,并根据map的key来查找map的value。需要注意的点有以下几个:

  • 可以看出map实际上是一个模板类,我们使用语句map<string, double> sal;实际上就是创建了一个map对象sal,这个sal对象本身具有一些方法,如begin、end、insert等。
  • 引入string库可以建立string数组。
  • 因为要遍历map结构,所以需要建立遍历器iterator。
  • 使用insert方法插入时,格式为map.insert(make_pair(foo, bar));
  • map具有begin和end两个方法,两者的返回值并不是一个简单的数字,而是遍历器iterator值,通过iterator的first和second属性可以分别访问到map的key和value。
  • map的添加除了使用insert方法外,还可以使用 下标法 插入。
  • 在map表中查询时,需要将整个map结构进行遍历。

介绍了map之后,我们就可以试着读取cfg文件中的项目配置信息了。

首先,我们要知道cfg文件的格式,右边都是 key = value 这种格式,并且,我么可以使用 # 作为注释的标记符号。如下

#this is a comment
a =
b = #this comment is valid # this is another
c =

上面就是注释的两种使用,一种单独占用一行,另外一种在K-V之后添加。

这一部分,我们也可以写成一个c++工程,那么一般就要有.h和.cpp文件,在主程序cpp文件中,是逻辑程序,所以,一些方法的定义最好定义在其他文件中,一般,我们定义在.h文件中,然后在对应的cpp文件中补充,这样,在主程序中,我们就可以引入.h文件来简化程序,使得程序的表达更为清晰、高效,如下,我们建立get_config.h文件:

#ifndef __GET_CONFIG_H__
#define __GET_CONFIG_H__ #include <string>
#include <map>
#include <iostream>
using namespace std; #define COMMENT_CHAR '#' bool ReadConfig(const string & filename, map <string, string> & m);
void PrintConfig(const map<string, string> & m);
void FindInConfig(map<string, string> m, string key);
#endif

这里 #define COMMENT '#'是宏定义的方式,易于扩展和重构,增加程序的效率,下面的两句定义了两个函数,一个是读取配置信息的函数,另外一个是打印所有配置信息的函数,实参中的 & 是引用,这样就不是简单的赋值,而是修改实参同时也在修改传递进来的值。

  • 我们在这里引入了 string、map、iostream,这样,在main.cpp中我们就不需要重复引入这些了。
  • 使用COMMENT_CHAR更为清晰易懂一些。
  • 这里定义了一些主要的函数,是为了在main.cpp使用,而get_config.cpp中的其他函数都是实现,而非接口。

下面是get_config.cpp文件的代码:

#include "get_config.h"

#include <fstream>
#include <iostream> using namespace std; bool IsSpace(char c)
{
if (c == ' ' || c == '\t')
{
return true;
}
else
{
return false;
}
} bool IsCommentChar(char c)
{
if (c == COMMENT_CHAR)
{
return true;
}
else
{
return false;
}
} // trim函数的作用是把一个字符串左边和右边的空格去掉,即为trim
void Trim(string & str) // 引用传参,这样在函数中修改该参数也会修改相应的变量
{
if (str.empty())
{
return;
}
int i, start_pos, end_pos;
for (i = ; i < str.size(); i++)
{
if (!IsSpace(str[i]))
{
break;
}
}
if (i == str.size())
{
str = "";
return;
}
start_pos = i; // 获取到非空格的初始位置 for (i = str.size() - ; i >= ; i--)
{
if (!IsSpace(str[i]))
{
break;
}
}
end_pos = i;
str = str.substr(start_pos, end_pos - start_pos + );
} bool AnalyseLine(const string & line, string & key, string & value) // 分析一行,如果是注释行,则不处理,如果是k-v行,则提取出key-value值。
{
if (line.empty())
{
return false;
}
int start_pos = , end_pos = line.size() - , pos;
if ((pos = line.find(COMMENT_CHAR)) != -)
{
if ( == pos)
{
return false; // 如果一行的开头是#,说明是注释,则 不需要
}
end_pos = pos - ; // 可能是注释在k-v后的情况
}
string new_line = line.substr(start_pos, end_pos - start_pos + ); // 删掉后半部分的注释 FIX_ME: 这里应该是减错了吧
// 下面pos的赋值时必要的,这样,就可在后面得到Key和value值了。
if ((pos = new_line.find("=")) == -) //说明前面没有 = 号
{
return false;
}
key = new_line.substr(, pos); // 获得key
value = new_line.substr(pos + , end_pos + - (pos + )); // 获得value
Trim(key);
if (key.empty())
{
return false;
}
Trim(value); // 因为这里的key和value都是引用传递,可以直接被修改,所以不用返回
return true;
} // 读取一个cfg文件并保存到map中,map中的key和value都是string类型的。
bool ReadConfig(const string & filename, map<string, string> & m)
{
m.clear(); // 删除map容器中的所有k-v对
ifstream infile(filename.c_str());
if (!infile)
{
cout << "file open failed!" << endl; // 文件打开失败,返回错误信息。
return false;
}
string line, key, value; // 为了后续保存kv对
while (getline(infile, line))
{
if (AnalyseLine(line, key, value))
{
m[key] = value; // 保存到map容器中的方法。
}
}
infile.close(); // 当读取完之后,就要关闭这个文件。
return true;
} void PrintConfig(const map<string, string> & m)
{
map<string, string>::const_iterator mite;
for (mite = m.begin(); mite != m.end(); mite++)
{
cout << mite->first << "=" << mite->second << endl;
}
} void FindInConfig( map<string, string> m, string key) // 注意:之前用的一直都是string类型,所以这里用的也是string key,而不是char key。
{
map<string, string>::iterator it;
it = m.find(key);
if (it == m.end())
{
cout << "there is no " << key << endl;
}
else
{
cout << it->second << endl;
}
}
  • 这里通过map实现了cfg文件中kv对的存取,方便操作。
  • 注意这里的文件读取的操作,已经getline等相关函数。
  • 注意整体的逻辑: 打开文件、从上到下获取行、注释忽略、建立map、存取kv对,这样,我们就可以得到cfg文件中所有有用的参数了。
  • 最后FindInConfig函数中,我们将找到的kv输出,当然,在使用过程中,我们可以直接获取进行进一步的计算工作。

如下是main.cpp中的代码:

#include "get_config.h"
int main()
{
map<string, string> m;
ReadConfig("C:\\Users\\Administrator\\Desktop\\readConfig\\readConfig\\config.cfg", m);
PrintConfig(m);
string key;
cout << "Please input a key to find the value in config.cfg" << endl;
cin >> key;
FindInConfig(m, key);
return ;
}
  • 这里使用了绝对位置。
  • main.cpp中只需引入get_config.h文件,而main.cpp就相当于入口文件。

我们通过运行,可以得到下面的运行结果:

STL简洁 && c++读取cfg文件

STL简洁 && c++读取cfg文件

如上所示。

通过上上面的小工程,我们就可以完成对cfg文件的读取工作了。

STL简洁 && c++读取cfg文件的更多相关文章

  1. 读取XML文件内容

    myeclipse中类的格式 上面中的RunMain.java为程序执行的入口,JdbcUtil.java为实体类,XmlDocumentUtil.java执行解释xml文件与获取里面的属性,程序所需 ...

  2. Python读取大文件的&quot&semi;坑&OpenCurlyDoubleQuote;与内存占用检测

    python读写文件的api都很简单,一不留神就容易踩"坑".笔者记录一次踩坑历程,并且给了一些总结,希望到大家在使用python的过程之中,能够避免一些可能产生隐患的代码. 1. ...

  3. Configutation读取properties文件信息

    commons configuration可以很方便的访问配置文件和xml文件中的的内容.Commons Configuration 是为了提供对属性文件.XML文件.JNDI资源.来自JDBC Da ...

  4. JavaScript日历控件开发 C&num; 读取 appconfig文件配置数据库连接字符串,和配置文件 List&lt&semi;T&gt&semi;&period;ForEach 调用异步方法的意外 ef 增加或者更新的习惯思维 asp&period;net core导入excel 一个二级联动

    JavaScript日历控件开发   概述 在开篇之前,先附上日历的代码地址和演示地址,代码是本文要分析的代码,演示效果是本文要实现的效果代码地址:https://github.com/aspwebc ...

  5. 用Python读取大文件

    通常我们在读取文件的时候,会用到read(), readline(), readlines(). 通常可能会有这样的用法: def test1(): with open("/tmp/test ...

  6. Unity3D移动平台动态读取外部文件全解析

    前言: 一直有个想法,就是把工作中遇到的坑通过自己的深挖,总结成一套相同问题的解决方案供各位同行拍砖探讨.眼瞅着2015年第一个工作日就要来到了,小匹夫也休息的差不多了,寻思着也该写点东西活动活动大脑 ...

  7. python读取caffemodel文件

    caffemodel是二进制的protobuf文件,利用protobuf的python接口可以读取它,解析出需要的内容 不少算法都是用预训练模型在自己数据上微调,即加载"caffemodel ...

  8. informatica读取FTP文件

    以下为一个完整的informatica读取ftp文件,并导入到系统中. 第一步: 通过shell脚本下载压缩包文件 /server/infa_shared/crm_prod/shell/ftpFrom ...

  9. Java读取word文件,字体,颜色

    在Android读取Word文件时,在网上查看时可以用tm-extractors,但好像没有提到怎么读取Word文档中字体的颜色,字体,上下标等相关的属性.但由于需要,要把doc文档中的内容(字体,下 ...

随机推荐

  1. UVa 445 - Marvelous Mazes

    https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=94&page=s ...

  2. html5 表单样式 表单验证1 2 3

    html5 表单样式 ie9以下不支持 <!DOCTYPE html> <html lang="en"> <head> <meta cha ...

  3. 分享一个使用APICloud云数据库已上线的商城APP

    本项目盈利模式依赖taobao模块实现淘宝闭环交易,发布销售淘宝联盟产品获取返佣.目前已在应用宝上线安卓版本,先上图. 源码在此: http://community.apicloud.com/bbs/ ...

  4. apache 多域名配置

    一直不明白apache多域名配置的问题,所以只能用不同的端口来配置,现在终于搞懂了一点 首先,开启apache的vhost模块 找到配置文件httpd.conf中的下面两行 #LoadModule v ...

  5. Wowza流媒体Live直播和VOD点播配置实战

    Wowza是当今可以说最流行的流媒体服务器之一,近来因为需要搭建相应的服务器,但又不想用camera等作真实的直播,所以想办法用媒体文件转换成直播流再提供给Wowza进行直播.这里把该设置步骤以及设计 ...

  6. STM32F0使用LL库实现SHT70通讯

    在本次项目中,限于空间要求我们选用了STM32F030F4作为控制芯片.这款MCU不但封装紧凑,而且自带的Flash空间也非常有限,所以我们选择了LL库实现.本篇我们将基于LL库采用模拟I2C接口的方 ...

  7. java中的异常类

    Java中的异常: 1. Throwable是所有异常的根,java.lang.Throwable Throwable包含了错误(Error)和异常(Exception),Exception又包含了运 ...

  8. Android---Hellow World

    在搭建好了Android的开发环境后,接下来要做的事情就是开始开发我们的第一个Android应用程序---Hello World. 1.我们新建一个android项目: Application Nam ...

  9. ethers&period;js-4-Contracts

    Contracts A Contract is an abstraction of an executable program on the Ethereum Blockchain. A Contra ...

  10. JSON数据填充表格——(三)

    1.定义页面请求JSON的按钮与定义一个带表头的表格  请求数据的按钮 <button class="btn btn-primary search_bar_button floatR& ...