前言

系统程序一般需要读取参数文件,看到一个很好的Config类记录在此。

头文件Config.h

//Config.h
//re: https://blog.csdn.net/David_xtd/article/details/9320549
#pragma once #include <string>
#include <map>
#include <iostream>
#include <fstream>
#include <sstream> /*
* \brief Generic configuration Class
*
*/
class Config {
// Data
protected:
std::string m_Delimiter; //!< separator between key and value
std::string m_Comment; //!< separator between value and comments
std::map<std::string,std::string> m_Contents; //!< extracted keys and values typedef std::map<std::string,std::string>::iterator mapi;
typedef std::map<std::string,std::string>::const_iterator mapci;
// Methods
public: Config( std::string filename,std::string delimiter = "=",std::string comment = "#" );
Config();
template<class T> T Read( const std::string& in_key ) const; //!<Search for key and read value or optional default value, call as read<T>
template<class T> T Read( const std::string& in_key, const T& in_value ) const;
template<class T> bool ReadInto( T& out_var, const std::string& in_key ) const;
template<class T>
bool ReadInto( T& out_var, const std::string& in_key, const T& in_value ) const;
bool FileExist(std::string filename);
void ReadFile(std::string filename,std::string delimiter = "=",std::string comment = "#" ); // Check whether key exists in configuration
bool KeyExists( const std::string& in_key ) const; // Modify keys and values
template<class T> void Add( const std::string& in_key, const T& in_value );
void Remove( const std::string& in_key ); // Check or change configuration syntax
std::string GetDelimiter() const { return m_Delimiter; }
std::string GetComment() const { return m_Comment; }
std::string SetDelimiter( const std::string& in_s )
{ std::string old = m_Delimiter; m_Delimiter = in_s; return old; }
std::string SetComment( const std::string& in_s )
{ std::string old = m_Comment; m_Comment = in_s; return old; } // Write or read configuration
friend std::ostream& operator<<( std::ostream& os, const Config& cf );
friend std::istream& operator>>( std::istream& is, Config& cf ); protected:
template<class T> static std::string T_as_string( const T& t );
template<class T> static T string_as_T( const std::string& s );
static void Trim( std::string& inout_s ); // Exception types
public:
struct File_not_found {
std::string filename;
File_not_found( const std::string& filename_ = std::string() )
: filename(filename_) {} };
struct Key_not_found { // thrown only by T read(key) variant of read()
std::string key;
Key_not_found( const std::string& key_ = std::string() )
: key(key_) {} };
}; /* static */
template<class T>
std::string Config::T_as_string( const T& t )
{
// Convert from a T to a string
// Type T must support << operator
std::ostringstream ost;
ost << t;
return ost.str();
} /* static */
template<class T>
T Config::string_as_T( const std::string& s )
{
// Convert from a string to a T
// Type T must support >> operator
T t;
std::istringstream ist(s);
ist >> t;
return t;
} /* static */
template<>
inline std::string Config::string_as_T<std::string>( const std::string& s )
{
// Convert from a string to a string
// In other words, do nothing
return s;
} /* static */
template<>
inline bool Config::string_as_T<bool>( const std::string& s )
{
// Convert from a string to a bool
// Interpret "false", "F", "no", "n", "0" as false
// Interpret "true", "T", "yes", "y", "1", "-1", or anything else as true
bool b = true;
std::string sup = s;
for( std::string::iterator p = sup.begin(); p != sup.end(); ++p )
*p = toupper(*p); // make string all caps
if( sup==std::string("FALSE") || sup==std::string("F") ||
sup==std::string("NO") || sup==std::string("N") ||
sup==std::string("") || sup==std::string("NONE") )
b = false;
return b;
} template<class T>
T Config::Read( const std::string& key ) const
{
// Read the value corresponding to key
mapci p = m_Contents.find(key);
if( p == m_Contents.end() ) throw Key_not_found(key);
return string_as_T<T>( p->second );
} template<class T>
T Config::Read( const std::string& key, const T& value ) const
{
// Return the value corresponding to key or given default value
// if key is not found
mapci p = m_Contents.find(key);
if( p == m_Contents.end() ) return value;
return string_as_T<T>( p->second );
} template<class T>
bool Config::ReadInto( T& var, const std::string& key ) const
{
// Get the value corresponding to key and store in var
// Return true if key is found
// Otherwise leave var untouched
mapci p = m_Contents.find(key);
bool found = ( p != m_Contents.end() );
if( found ) var = string_as_T<T>( p->second );
return found;
} template<class T>
bool Config::ReadInto( T& var, const std::string& key, const T& value ) const
{
// Get the value corresponding to key and store in var
// Return true if key is found
// Otherwise set var to given default
mapci p = m_Contents.find(key);
bool found = ( p != m_Contents.end() );
if( found )
var = string_as_T<T>( p->second );
else
var = value;
return found;
} template<class T>
void Config::Add( const std::string& in_key, const T& value )
{
// Add a key with given value
std::string v = T_as_string( value );
std::string key=in_key;
Trim(key);
Trim(v);
m_Contents[key] = v;
return;
}

源文件Config.cpp

// Config.cpp  

#include "Config.h"  

using namespace std;  

Config::Config( string filename, string delimiter,
string comment )
: m_Delimiter(delimiter), m_Comment(comment)
{
// Construct a Config, getting keys and values from given file std::ifstream in( filename.c_str() ); if( !in ) throw File_not_found( filename ); in >> (*this);
} Config::Config()
: m_Delimiter( string(,'=') ), m_Comment( string(,'#') )
{
// Construct a Config without a file; empty
} bool Config::KeyExists( const string& key ) const
{
// Indicate whether key is found
mapci p = m_Contents.find( key );
return ( p != m_Contents.end() );
} /* static */
void Config::Trim( string& inout_s )
{
// Remove leading and trailing whitespace
static const char whitespace[] = " \n\t\v\r\f";
inout_s.erase( , inout_s.find_first_not_of(whitespace) );
inout_s.erase( inout_s.find_last_not_of(whitespace) + 1U );
} std::ostream& operator<<( std::ostream& os, const Config& cf )
{
// Save a Config to os
for( Config::mapci p = cf.m_Contents.begin();
p != cf.m_Contents.end();
++p )
{
os << p->first << " " << cf.m_Delimiter << " ";
os << p->second << std::endl;
}
return os;
} void Config::Remove( const string& key )
{
// Remove key and its value
m_Contents.erase( m_Contents.find( key ) );
return;
} std::istream& operator>>( std::istream& is, Config& cf )
{
// Load a Config from is
// Read in keys and values, keeping internal whitespace
typedef string::size_type pos;
const string& delim = cf.m_Delimiter; // separator
const string& comm = cf.m_Comment; // comment
const pos skip = delim.length(); // length of separator string nextline = ""; // might need to read ahead to see where value ends while( is || nextline.length() > )
{
// Read an entire line at a time
string line;
if( nextline.length() > )
{
line = nextline; // we read ahead; use it now
nextline = "";
}
else
{
std::getline( is, line );
} // Ignore comments
line = line.substr( , line.find(comm) ); // Parse the line if it contains a delimiter
pos delimPos = line.find( delim );
if( delimPos < string::npos )
{
// Extract the key
string key = line.substr( , delimPos );
line.replace( , delimPos+skip, "" ); // See if value continues on the next line
// Stop at blank line, next line with a key, end of stream,
// or end of file sentry
bool terminate = false;
while( !terminate && is )
{
std::getline( is, nextline );
terminate = true; string nlcopy = nextline;
Config::Trim(nlcopy);
if( nlcopy == "" ) continue; nextline = nextline.substr( , nextline.find(comm) );
if( nextline.find(delim) != string::npos )
continue; nlcopy = nextline;
Config::Trim(nlcopy);
if( nlcopy != "" ) line += "\n";
line += nextline;
terminate = false;
} // Store key and value
Config::Trim(key);
Config::Trim(line);
cf.m_Contents[key] = line; // overwrites if key is repeated
}
} return is;
}
bool Config::FileExist(std::string filename)
{
bool exist= false;
std::ifstream in( filename.c_str() );
if( in )
exist = true;
return exist;
} void Config::ReadFile( string filename, string delimiter,
string comment )
{
m_Delimiter = delimiter;
m_Comment = comment;
std::ifstream in( filename.c_str() ); if( !in ) throw File_not_found( filename ); in >> (*this);
}

主程序测试文件main.cpp

//main.cpp
#include "Config.h"
int main()
{
int port;
std::string ipAddress;
std::string username;
std::string password;
const char ConfigFile[]= "..//src//config.txt";
Config configSettings(ConfigFile); port = configSettings.Read("port", );
ipAddress = configSettings.Read("ipAddress", ipAddress);
username = configSettings.Read("username", username);
password = configSettings.Read("password", password);
std::cout<<"port:"<<port<<std::endl;
std::cout<<"ipAddress:"<<ipAddress<<std::endl;
std::cout<<"username:"<<username<<std::endl;
std::cout<<"password:"<<password<<std::endl;
//
float level = configSettings.Read("level", level);
std::cout<<"level:"<<level<<std::endl; return ;
}

参数配置文件实例config.txt

ipAddress=10.10.90.125
port = ;
username=mark
password=2d2df5a
level = 0.11

疑问

1. 头文件中Config类定义之后的函数为什么要写在文件内类外呢?可以写到源文件中吗?

参考

1. 使用Config类读取配置文件

【c++基础】C++编写Config类读取配置文件的更多相关文章

  1. C++编写Config类读取配置文件

    老外写的一段代码,在Server中编写这个类读取配置文件比较实用 //Config.h #pragma once #include <string> #include <map> ...

  2. [转]C++编写Config类读取配置文件

    //Config.h #pragma once #include <string> #include <map> #include <iostream> #incl ...

  3. Java 数据类型:集合接口Map:HashTable;HashMap;IdentityHashMap;LinkedHashMap;Properties类读取配置文件;SortedMap接口和TreeMap实现类:【线程安全的ConcurrentHashMap】

    Map集合java.util.Map Map用于保存具有映射关系的数据,因此Map集合里保存着两个值,一个是用于保存Map里的key,另外一组值用于保存Map里的value.key和value都可以是 ...

  4. java properties类读取配置文件

    1.JAVA Properties类,在java.util包里,具体类是java.util.properties.Properties类继承自Hashtable类并且实现了Map接口,也是使用一种键值 ...

  5. java-工具类-读取配置文件

    java读取配置文件,当发现文件被修改后则重新加载 package com.zg.config; import java.io.File; import java.io.FileInputStream ...

  6. 阶段3 2.Spring_02.程序间耦合_5 编写工厂类和配置文件

    先把dao的实现复制一份到别的地方.然后删除项目里面的AccountDaoImpl这个dao的实现类 删除 service层就开始报错了 这个时候运行直接报错 把文件复制回来就不报错了 解决依赖关系 ...

  7. Properties类读取配置文件

    package com.wzy.t4; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFound ...

  8. java读取配置文件方法以及工具类

    第一种方式 : java工具类读取配置文件工具类 只是案例代码  抓取异常以后的代码自己处理 import java.io.FileNotFoundException; import java.io. ...

  9. selenium3+java+POM 跨浏览器测试之------读取配置文件

    我们知道,web 测试的时候是需要切换不同的浏览器以查看每个功能在不同浏览器上的运行情况,使得开发的程序更具有健壮性.本文先总结一下如何通过读取配置文件来切换浏览器. 具体步骤如下: 一.编写配置文件 ...

随机推荐

  1. 【C++/html版 代码 : 暴力破解数字红包 】-- 只要有编译器或者,不看运气,用手速敲代码说话,多人合作效果更佳!

    需求分析: 或者是更大的范围! 是不是很捉急!运气背点不就over了! C++版: #include <stdio.h> #include <stdlib.h> #includ ...

  2. Vue入门——v-if和v-show

    v-if 特点:每次都会重新删除或创元素 有较高的切换性能消耗 v-show 特点:每次不会重新进行DOM的删除和创建操作,只是切换了元素的display:none样式 有较高的初始渲染消耗

  3. 多线程爬取猫眼电影TOP100并保存到mongo数据库中

    import requests import re import json from requests.exceptions import RequestException from multipro ...

  4. IDEA创建类似于Eclipse的source folder

    1.新建普通文件夹目录directory 2.当前Module右键Open Mudule Settings(F12) 3.选中新建的文件夹并单击上面的Sources,看到文件夹颜色变化即成功.

  5. SQL Server Report Server

    1.SQL Server Report Server是利用mircosoft的share point产品 在menu 打开Reporting Services Configuration进行配置,会自 ...

  6. ueditor+word粘贴上传!

    图片的复制无非有两种方法,一种是图片直接上传到服务器,另外一种转换成二进制流的base64码 目前限chrome浏览器使用,但是项目要求需要支持所有的浏览器,包括Windows和macOS系统.没有办 ...

  7. vue-ckeditor-word粘贴

    我司需要做一个需求,就是使用富文本编辑器时,不要以上传附件的形式上传图片,而是以复制粘贴的形式上传图片. 在网上找了一下,有一个插件支持这个功能. WordPaster 安装方式如下: 直接使用Wor ...

  8. Til the Cows Come Home ( POJ 2387) (简单最短路 Dijkstra)

    problem Bessie is out in the field and wants to get back to the barn to get as much sleep as possibl ...

  9. IDEA算法导包后 import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey;报错

    仔细查看报错原因就能知道,报错是因为包冲突的原因,可以每种只放一个jar包,就能过避免这种错误. 例如:只导入commons-codec-1.11-javadoc,jar和bcprov-jdk15on ...

  10. SNMP 协议介绍 转载

    一.SNMP简单概述 1.1.什么是Snmp SNMP是英文"Simple Network Management Protocol"的缩写,中文意思是"简单网络管理协议& ...