地点:基地
时间:2014.03.20
------------------------------------------------------------------------------
一、string流简述
前面我们已经说道,标准库中定义IO类型的有三个头文件:iostream 定义; 用于读写流的基本类型,fstream定义了读写命名文件的类型,sstream定义了读写内存string对象的类型。其中在sstring头文件中定义了三个类型来支持内存IO,这些类型可以向string中写入数据,从string读取数据,就像string是一个IO流一样。
相关列出如下:
1. istringstream 从string读取数据。
2. ostringstream 向string写入数据。
3. stringstream 既可从string读取数据也可向string写数据。
和前面fstream一样,sstream也是继承自iostream,另外也有些新的东西假如,总结如下:
sstream strm; //strm是一个未绑定的stringstream对
sstream strm(s); //strm是一个sstream对象,保存string s的一个拷贝,此构造函数explicit
strm.str(); //返回strm所保存的string的拷贝
strm.str(s); //将string s拷贝到strm中,返回void
------------------------------------------------------------------------------
二、使用istringstream
当你想对整行文本进行处理,而其他一些工作时处理行内的单个单词时,通常使用istringstream。
任务:假如有一个文件,列出了一些人和他们的电话号码,某些人只有一个号码,而某些人则有多个:家庭电话,工作电话,移动电话。输入文件可能是这样;
morgan 13332517100
drew 13336547895 13335247654
jim 13336547126 13335647856 13335267865
即文件中每条记录都以一个人名开始,后面跟若干个电话号码,我们可以先定定义一个数据结构来描述:
struct PersonInfo{ string name; vector<string> phonses; };有了这样一个结构后,我们可以创建一个PersonInfo的vector。vector中的每个元素对应文件中的一条记录。我们可通过循环读取数据,每个循环读取一条记录,然后提取个人姓名和电话号码信息,实现如下:
string line,word; //分别用来保存来自输入的一行和单词 vector<PersonInfo> people; //保存来自输入的所有记录 while(getline(cin,line)){ //逐行读取数据直到cin遇到文件尾或者其它错误 PersonInfo info; //创建一个保存一条数据记录的PersonInfo对象 istringstream record(line); //将记录绑定到刚读入的行信息 while(record>>word) //读取电话号码 info.phones.push_back(word); //保持它们 people.push_back(info); //将此记录追加到people末尾 }这里我们先用getline从标准输入读取整条记录(一行),然后将istringstream与该条记录进行绑定,现在我们就可以把该部分内存就像一个IO那样去使用它了,可实现在一个循环里,依次将数据读入构造一个PersonInfo对象,当string数据全部读出后,同样也会触发一个“文件结束”信号,退出循环,并将构造好的对象追加到vector中。
------------------------------------------------------------------------------
三、使用ostringstream
继续延续上面的例子,现在假如我们想逐个验证我们得到的用户电话号码并改变其输出格式:有效号码按规定输出到一个新文件,无效号码则是打印人名和无效号码的对应信息。因此,现在我们应该先针对每条记录先“写入”到一个内存ostringstream中,验证完所有电话号码后才进行输出操作。实现如下(程序中valid和format为假定已有的函数,分别完成电话号码的验证和改变格式的功能):
for(const auto &entry:people){ //对people中的每一项 ostringstream formatted,badNums; //每个循环步都创建的对象性 for(const auto &nums:entry.phonse){ //对每条记录中的电话号码 if(!valid(nums)){ badNums<<" "<<nums; //将数的字符串形式存入badNums }else formatted<<" "<<format(nums); //将格式化的字符串“写入”formatted } if(badNums.str().empty()) //没有错误的数 os<<entry.name<<" "<<formatted.str()<<endl; //打印名字和格式化的数 else //否则打印名字和错误的数 cerr<<"input error: "<<entry.name <<“ invalid number(s) "<<badNums.str()<<endl;------------------------------------------------------------------------------
四、总结
总结来说:
1.iostream处理控制台IO
2.fstream 处理命名文件IO
3.stringstream完成内存string的IO
后两者都继承自iostream,因此很大程度上都能执行一样的操作。
另外,每个IO对象都还会维护一组条件状态,用来指出此对象上是否可进行IO操作或者遇到什么样的错误,标准库中提供一组函数,可用来设置和检测这些状态。