用line_as_stream 简化流的读取

本文介绍了一种确保文件中数组元素正确读写的技巧。通过使用line_as_stream方法来逐行读取数据,即使文件中出现损坏行,也能防止数据错位,确保其他元素的正确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script> 在将数据持久化到文件时,你可能会发现很难强制要求系统将特定的部分数据写到一行中。将特定的数据写到同一行有时是很有用的,比如在你从流(如一个文件)中读取一个数组的时候。 假设你要读取一个数组的元素,其中有一行被破坏了(比如丢失了一些数据)。一般情况下,这会导致后面所有的元素都受损。 作为一个例子,假设我们有一个数据结构,是一个窗口数组,你希望把它持久化到一个文件中,象下面这样: 第一行:窗口的数量 后面的每一行都包含两个值:窗口的宽度和窗口的高度 写成代码似乎很简单: #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; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值