分享
 
 
 

用line_as_stream 简化流的读取

王朝other·作者佚名  2008-05-31
窄屏简体版  字體: |||超大  

在将数据持久化到文件时,你可能会发现很难强制要求系统将特定的部分数据写到一行中。将特定的数据写到同一行有时是很有用的,比如在你从流(如一个文件)中读取一个数组的时候。

假设你要读取一个数组的元素,其中有一行被破坏了(比如丢失了一些数据)。一般情况下,这会导致后面所有的元素都受损。

作为一个例子,假设我们有一个数据结构,是一个窗口数组,你希望把它持久化到一个文件中,象下面这样:

第一行:窗口的数量

后面的每一行都包含两个值:窗口的宽度和窗口的高度

写成代码似乎很简单:

#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;

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有