xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
许多开发者抱怨c++不能像java那样绑定properties类。java的properties类内在包含一个文件,该文件用来读写properties类中的属性,可以写成这样形式:<名字>=<数值>(例如:connecttointe.net=use ie)。
使用properties类的好处就是你可以很轻松的理解和修改它们。在本文的第一部分中,你将看到我们也可以在c++中使用properties类。本文的第二部分将向你演示通过使用操作符>>和<<把数据保存到properties类中是多么的容易。
现在介绍c++ properties文件的结构。该文件的每一行可以是下面三种情况中的某一种:
空行(认为它是注释中的一部分)
以‘#’ 开始的注释行
‘<名字>=<数值>’行,这是给一个属性赋值的语句
现在让我们再看看properties类的的特点:
注释是持久性的(当保存properties类时,它们不会丢失掉)。注意每一个注释都属于某个属性。在‘<名字>=<数值>’行上的注释行属于该‘<名字>’属性。
当保存properties类后,属性仍然保留自己的位置。
它对各种字符类型都有效:char、wchar_t等等
properties类的使用相当简单:
save():保存属性
has_property(strpropertyname):如果类中有该属性则返回‘真’
string get_property(strpropertyname):返回指定的属性(如果指定属性不存在,则抛出例外)
set_property(strpropertyname, strpropertyvalue):设置给定属性
stringget_property_comment( strpropertyname):返回属于指定属性的注释(如果指定属性的注释不存在,则抛出例外)
set_property_comment(strpropertyname, strpropertycomment):设置指定属性的注释(如果指定属性的注释不存在,则抛出例外)
下面是file_reader_writer类以及相应例子的代码。运行它之后,请查看properties.txt文件。看看访问和修改它是多么容易的一件事。
#include exception>
#include string>
#include sstream>
#include map>
#include vector>
#include fstream>
#include algorithm>
#include functional>
//允许字符串转化
template< class fromchartype, class tochartype>
inline std::basic_string< tochartype> convert_string( const std::basic_string< fromchartype> & strsource)
{
std::basic_string< tochartype> strdest;
int nsourcelen = strsource.length();
strdest.resize( nsourcelen);
for ( int idxchar = 0; idxchar < nsourcelen; idxchar++)
{ strdest[ idxchar] = ( tochartype)strsource[ idxchar]; }
return strdest;
}
// 用于trim_spaces;
template< class chartype>
struct is_char_in_str : public std::binary_function< chartype, std::basic_string< chartype>, bool>
{
bool operator()( chartype ch, const std::basic_string< chartype> & strsource) const
{ return (strsource.find( ch) != std::basic_string< chartype>::npos); }
};
//消除字符串中的空格
template< class chartype>
std::basic_string< chartype> trim_spaces( const std::basic_string< chartype> & strsource)
{
std::basic_string< chartype> strspaces; strspaces += ( chartype)' '; strspaces += ( chartype)'\t';
typedef std::basic_string< chartype> string_type;
string_type::const_iterator
itfirst = std::find_if( strsource.begin(), strsource.end(),
std::not1( std::bind2nd( is_char_in_str< chartype>(), strspaces)));
string_type::const_reverse_iterator
ritlast = std::find_if( strsource.rbegin(), strsource.rend(),
std::not1( std::bind2nd( is_char_in_str< chartype>(), strspaces)));
string_type::const_iterator itlast = &*ritlast;
if ( itfirst <= itlast)
if ( itfirst != strsource.end())
return string_type( itfirst, itlast + 1);
return string_type();
}
// 当读写属性时的例外
class properties_exception : public std::exception
{
public:
properties_exception( const std::string & str) : m_strdescription( str) {}
const char * what() const { return m_strdescription.c_str(); }
private:
std::string m_strdescription;
};
// 从文件中读写属性
template< class chartype>
class file_reader_writer
{
typedef std::basic_string< chartype> string_type;
public:
// ... needed within the basic_properties!
typedef chartype char_type;
public:
file_reader_writer( const char * strfilename)
: m_bisdirty( false), m_strfilename( strfilename) { read_properties(); }
~file_reader_writer() { save(); }
void save()
{ write_properties(); }
bool has_property( const string_type & strpropertyname) const
{
propertiescollection::const_iterator itfound = m_collproperties.find( strpropertyname);
return ( itfound != m_collproperties.end());
}
const string_type & get_property( const string_type & strpropertyname) const
{
propertiescollection::const_iterator itfound = m_collproperties.find( strpropertyname);
if ( itfound != m_collproperties.end())
return itfound->second.m_strvalue;
else
throw properties_exception(
"cound not get property value for '" + convert_string< char_type, char>( strpropertyname) +
"', since this property does not exist.");
}
void set_property( const string_type & strproperty, const string_type & strpropertyvalue)
{
propertiescollection::iterator itfound = m_collproperties.find( strproperty);
if ( itfound == m_collproperties.end())
// 它是一个新的属性
m_aproperties.push_back( strproperty);
m_collproperties[ strproperty].m_strvalue = strpropertyvalue;
m_bisdirty = true;
}
const string_type & get_property_comment( const string_type & strpropertyname) const
{
propertiescollection::const_iterator itfound = m_collproperties.find( strpropertyname);
if ( itfound != m_collproperties.end())
return itfound->second.m_strcomment;
else
throw properties_exception(
"cound not get property comment for '" + convert_string< char_type, char>( strpropertyname) +
"', since this property does not exist.");
}
void set_property_comment( const string_type & strpropertyname, const string_type & strpropertycomment)
{
propertiescollection::iterator itfound = m_collproperties.find( strpropertyname);
if ( itfound != m_collproperties.end())
itfound->second.m_strcomment = strpropertycomment;
else
throw properties_exception(
"cound not set property comment for '" + convert_string< char_type, char>( strpropertyname) +
"', since this property does not exist.");
m_bisdirty = true;
}
private:
static const char_type get_delimeter() { return '='; }
static const char_type get_comment() { return '#'; }
void read_properties()
{
const char delimeter = get_delimeter();
const char comment = get_comment();
std::basic_ifstream< char_type> streamin( m_strfilename.c_str());
string_type strline;
string_type strcomment;
while ( std::getline( streamin, strline))
{
strline = trim_spaces( strline);
bool biscomment = strline.empty() ( strline[ 0] == comment);
if ( biscomment)
{ strcomment += strline; strcomment += '\n'; }
else
{
int idxdelimeter = strline.find( delimeter);
if ( idxdelimeter != string_type::npos)
{
string_type strpropertyname = strline.substr( 0, idxdelimeter);
string_type strpropertyvalue = strline.substr( idxdelimeter + 1);
strpropertyname = trim_spaces( strpropertyname);
strpropertyvalue = trim_spaces( strpropertyvalue);
m_collproperties.insert(
std::make_pair( strpropertyname, oneproperty( strpropertyvalue, strcomment)));
m_aproperties.push_back( strpropertyname);
strcomment.erase();
}
else
throw properties_exception(
"while reading from file '" + m_strfilename +
"', we encountered an invalid line: \n" + convert_string< char_type, char>( strline));
}
}
m_strlastcomment = strcomment;
}
void write_properties() const
{
if ( !m_bisdirty)
// 无需保存
;return;
const char delimeter = get_delimeter();
std::basic_ofstream< char_type> streamout( m_strfilename.c_str());
propertiesarray::const_iterator
itfirst = m_aproperties.begin(), itlast = m_aproperties.end();
while ( itfirst != itlast)
{
const string_type & strpropertyname = *itfirst;
const oneproperty & property = m_collproperties.find( strpropertyname)->second;
write_property_comment( streamout, property.m_strcomment);
string_type strtowrite = strpropertyname;
strtowrite += ' '; strtowrite += delimeter; strtowrite += ' ';
streamout strtowrite << property.m_strvalue << std::endl;
++itfirst;
}
write_property_comment( streamout, m_strlastcomment);
m_bisdirty = false;
}
void write_property_comment( std::basic_ofstream< char_type> & streamout, const string_type & strcomment) const
{
const char comment = get_comment();
std::basic_stringstream< char_type> streamcomment( strcomment);
string_type strline;
while ( std::getline( streamcomment, strline))
{
if ( !strline.empty())
if ( strline[ 0] == comment)
streamout << strline << std::endl;
else
{
string_type strprefix;
strprefix += comment; strprefix += ' ';
streamout << strprefix << strline << std::endl;
}
else
streamout << std::endl;
}
}
private:
// 我们用来读写的文件
std::string m_strfilename;
//如果自上次保存后属性又有修改则赋值为“真”
mutable bool m_bisdirty;
struct oneproperty
{
oneproperty() {}
oneproperty( const string_type & strvalue, const string_type & strcomment)
: m_strvalue( strvalue), m_strcomment( strcomment) {}
string_type m_strvalue;
string_type m_strcomment;
};
// 属性
typedef std::map< string_type, oneproperty> propertiescollection;
propertiescollection m_collproperties;
// ……确保我们是按同样的次序保存属性
// 读属性
typedef std::vector< string_type> propertiesarray;
propertiesarray m_aproperties;
// 读取所有属性后的注释
string_type m_strlastcomment;
};
下面是用到这个类的一个例子:
#include
int main(int argc, char* argv[])
{
file_reader_writer< char> rw( "properties.txt");
rw.set_property( "app path", "c:\program files\pfs\jokexplorer");
rw.set_property_comment( "app path", "where are we installed?");
rw.set_property( "version", "4.0.0.1");
rw.set_property_comment( "version", "what's our version?");
rw.set_property( "run on startup", "1");
rw.set_property_comment( "run on startup", "are we run, when the computer starts?");
rw.set_property( "automatic logoff minutes", "60");
rw.set_property_comment( "automatic logoff minutes", "when should we deconnect from the server?");
rw.set_property( "connect to inte.net", "use ie");
rw.set_property_comment( "connect to inte.net", "how are we to connect to the inte.net?");
std::cout << "this is how we connect to inte.net: " << rw.get_property( "connect to inte.net") << std::endl;
return 0;
}
Java Asp PHP .Net XML C/C++ CGI VB Jsp J2ee J2se J2me EJB Servlet Tomcat Resin Struts Weblogic Eclipse ANT GUI JMS Web servise IDEA Webphere Hibernate Spring Jboss Applet Swing Socket Javamail Perl Ajax P2P 安全 模式 框架 测试 开源 游戏
Windows XP Windows 2000 Windows 2003 Windows Me Windows 9.x Linux UNIX 注册表 操作系统 服务器 应用服务器