许多开发者抱怨C++不能像Java那样绑定Properties类。Java的Properties类内在包含一个文件,该文件用来读写Properties类中的属性,可" />
龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > 软件开发 > JAVA开发 >

使用Properties类带来的好处

时间:2009-12-23 15:42来源:未知 作者:admin 点击:
分享到:
?XML:namespace prefix = o ns = "urn:schemas-microsoft-com:Office:office" /> 许多开发者抱怨C++不能像Java那样绑定Properties类。Java的Properties类内在包含一个文件,该文件用来读写Properties类中的属性,可

<?XML:namespace prefix = o ns = "urn:schemas-microsoft-com:Office:office" /> 

许多开发者抱怨C++不能像Java那样绑定Properties类。Java的Properties类内在包含一个文件,该文件用来读写Properties类中的属性,可以写成这样形式:<名字>=<数值>(例如:ConnectToInternet=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)' ';
  
  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 += ' '; }
  
  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: " + 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 FilesPFSjokEXPlorer");
  
  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 Internet", "Use IE");
  
  rw.set_property_comment( "Connect To Internet", "how are we to connect to the Internet?");
  
  std::cout << "This is how we connect to Internet: " << rw.get_property( "Connect To Internet") << std::endl;
  
  return 0;
  
  }


  
精彩图集

赞助商链接