Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1529023
  • 博文数量: 3500
  • 博客积分: 6000
  • 博客等级: 准将
  • 技术积分: 43870
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-03 20:31
文章分类

全部博文(3500)

文章存档

2008年(3500)

我的朋友

分类:

2008-05-04 19:20:13

一起学习
在将数据持久化到文件时,你可能会发现很难强制要求系统将特定的部分数据写到一行中。将特定的数据写到同一行有时是很有用的,比如在你从流(如一个文件)中读取一个数组的时候。 假设你要读取一个数组的元素,其中有一行被破坏了(比如丢失了一些数据)。一般情况下,这会导致后面所有的元素都受损。 作为一个例子,假设我们有一个数据结构,是一个窗口数组,你希望把它持久化到一个文件中,象下面这样: 第一行:窗口的数量 后面的每一行都包含两个值:窗口的宽度和窗口的高度 写成代码似乎很简单: #include #include #include struct Window { Window( int nLength = 0, int nHeight = 0) : m_nWindowLength( nLength), m_nWindowHeight( nHeight) {} int m_nWindowLength; int m_nWindowHeight; }; std::ostream & operator << ( std::ostream & streamOut, const Window & value) { streamOut << value.m_nWindowLength << " " << value.m_nWindowHeight; return streamOut; } std::istream & operator >> ( std::istream & streamIn, Window & value) { streamIn >> value.m_nWindowLength >> value.m_nWindowHeight; return streamIn; } void write_windows( std::vector< Window> &aWindows, const char * strFileName) { std::ofstream streamOut( strFileName); // 第一行 streamOut << aWindows.size() << std::endl; // 其余行 std::vector< Window>::iterator itFirst = aWindows.begin(), itLast = aWindows.end(); while ( itFirst != itLast) { // 每个窗口的数据都在它自己那一行 streamOut << *itFirst << std::endl; itFirst; } } 但是,要正确地读出这些数据,可能会有一些问题: //可能出错!!! void read_windows( std::vector< Window> &aWindows, const char * strFileName) { aWindows.clear(); std::ifstream streamIn( strFileName); int nSize; streamIn >> nSize; for ( int idx = 0; idx < nSize; idx) { Window w; streamIn >> w; aWindows.push_back( w); } } 上面的代码并没有强制任何东西。所有数据都被放到一行中,这看起来没有什么问题。但如果用户不小心,修改了你的文件,插入了一个多余的值或删掉了一个值,那么后面所有的元素都会得到错误的值,而你的程序并不会意识到这一点。尝试运行一下下面的代码并仔细看看其中的注释: #include #include int main(int argc, char* argv[]) { std::vector< Window> aWindows; aWindows.push_back( Window( 100, 400)); aWindows.push_back( Window( 200, 400)); aWindows.push_back( Window( 400, 400)); aWindows.push_back( Window( 500, 500)); aWindows.push_back( Window( 600, 200)); aWindows.push_back( Window( 600, 400)); aWindows.push_back( Window( 600, 690)); write_windows( aWindows, "persist.txt"); std::vector< Window> aReadWindows; /* 在这里加一个调试断点; 修改persist.txt,删除第4行的第一个值*/ read_windows( aReadWindows, "persist.txt"); std::copy( aReadWindows.begin(), aReadWindows.end(), std::ostream_iterator< Window>( std::cout, "\n")); /*在这里加一个调试断点:看看你读了多少个错误的值! */ return 0; } 还好,你可以用来line_as_stream读取一行,然后将它看作一个流。用这种方法,你可以确定每个元素是从一行中读取的。于是,read_windows函数变成这样: void read_windows( std::vector< Window> &aWindows, const char * strFileName) { aWindows.clear(); std::ifstream streamIn( strFileName); int nSize; // 第一行 line_as_stream( streamIn) >> nSize; for ( int idx = 0; idx < nSize; idx) { Window w; //每个窗口的数据都在它自己那一行 line_as_stream( streamIn) >> w; aWindows.push_back( w); } } 现在,重新运行前面的例子,你可以看到只有一个元素受损,如你所料。 这就是line_as_stream的源码: #include #include #include namespace Private { template< class char_type, class char_traits> struct line_stream_holder { typedef line_stream_holder< char_type, char_traits> this_class; typedef std::basic_istringstream< char_type, char_traits> stream_type; typedef std::basic_string< char_type, char_traits> string_type; line_stream_holder( const string_type & value) : m_stream( value) {} line_stream_holder( const this_class & source) : m_stream( source.m_stream.str() ) {} // allow passing this stream in functions that // accept streams operator stream_type & () const { return m_stream; } private: mutable stream_type m_stream; }; template< class char_type, class char_traits, class value_type> inline typename line_stream_holder< char_type, char_traits>::stream_type & operator >> (const line_stream_holder< char_type, char_traits> & streamIn, value_type & value) { typedef typename line_stream_holder< char_type, char_traits>::stream_type stream_type; stream_type & underlyingStream = streamIn; underlyingStream >> value; return underlyingStream; } } // namespace Private template< class char_type, class char_traits> Private::line_stream_holder< char_type, char_traits> line_as_stream( std::basic_istream< char_type, char_traits> & streamIn, char_type chDelim = '\n') { std::basic_string< char_type, char_traits> strLine; std::getline( streamIn, strLine, chDelim); return strLine; } 下载本文示例代码


用line_as_stream 简化流的读取用line_as_stream 简化流的读取用line_as_stream 简化流的读取用line_as_stream 简化流的读取用line_as_stream 简化流的读取用line_as_stream 简化流的读取用line_as_stream 简化流的读取用line_as_stream 简化流的读取用line_as_stream 简化流的读取用line_as_stream 简化流的读取用line_as_stream 简化流的读取用line_as_stream 简化流的读取
阅读(162) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~