//Config.h
#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("0") || 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#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(1,'=') ), m_Comment( string(1,'#') ){ // 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( 0, 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() > 0 ) { // Read an entire line at a time string line; if( nextline.length() > 0 ) { line = nextline; // we read ahead; use it now nextline = ""; } else { std::getline( is, line ); } // Ignore comments line = line.substr( 0, 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( 0, delimPos ); line.replace( 0, 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( 0, 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#include "Config.h"int main(){ int port; std::string ipAddress; std::string username; std::string password; const char ConfigFile[]= "config.txt"; Config configSettings(ConfigFile); port = configSettings.Read("port", 0); 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; return 0;}
配置解析与管理:一种高效的方法
本文介绍了一种用于解析和管理配置文件的类,包括读取、写入、修改配置信息等功能,旨在提高配置管理的效率和灵活性。
601

被折叠的 条评论
为什么被折叠?



