简单常识——关于stream
从文件中读入一行
简单,这样就行了:
ifstreamifs("input.txt");
charbuf[1000];
ifs.getline(buf,sizeofbuf);
stringinput(buf);
当然,这样没有错,但是包含不必要的繁琐和拷贝,况且,如果一行超过1000个字符,就必须用一个循环和更麻烦的缓冲管理。下面这样岂不是更简单?
stringinput;
input.reserve(1000);
ifstreamifs("input.txt");
getline(ifs,input);
不仅简单,而且安全,因为全局函数getline会帮你处理缓冲区用完之类的麻烦,如果你不希望空间分配发生的太频繁,只需要多reserve一点空间。
这就是“简单常识”的含义,很多东西已经在那里,只是我一直没去用。
---------------------------------------------------------------------------
一次把整个文件读入一个string
我希望你的答案不要是这样:
stringinput;
while(!ifs.eof())
{
stringline;
getline(ifs,line);
input.append(line).append(1,'/n');
}
当然了,没有错,它能工作,但是下面的办法是不是更加符合C++的精神呢?
stringinput(
istreambuf_iterator<char>(instream.rdbuf()),
istreambuf_iterator<char>()
);
同样,事先分配空间对于性能可能有潜在的好处:
stringinput;
input.reserve(10000);
input.assign(
istreambuf_iterator<char>(ifs.rdbuf()),
istreambuf_iterator<char>()
);
很简单,不是么?但是这些却是我们经常忽略的事实。
补充一下,这样干是有问题的:
stringinput;
input.assign(
istream_iterator<char>(ifs),
istream_iterator<char>()
);
因为它会忽略所有的分隔符,你会得到一个纯“字符”的字符串。最后,如果你只是想把一个文件的内容读到另一个流,那没有比这更快的了:
fstreamfs("temp.txt");
cout<<fs.rdbuf();
因此,如果你要手工copy文件,这是最好的(如果不用操作系统的API):
ifstreamifs("in.txt");
ofstreamofs("out.txt");
ofs<<in.rdbuf();
-------------------------------------------------------------------------
open一个文件的那些选项
ios::inOpenfileforreading
ios::outOpenfileforwriting
ios::ateInitialposition:endoffile
ios::appEveryoutputisappendedattheendoffile
ios::truncIfthefilealreadyexisteditiserased
ios::binaryBinarymode
-------------------------------------------------------------------------
还有ios的那些flag
flag
effectifset
ios_base::boolalpha |
input/outputboolobjectsasalphabeticnames(true,false).
|
ios_base::dec |
input/outputintegerindecimalbaseformat.
|
ios_base::fixed |
outputfloatingpointvaluesinfixed-pointnotation.
|
ios_base::hex |
input/outputintegerinhexadecimalbaseformat.
|
ios_base::internal |
theoutputisfilledataninternalpointenlargingtheoutputuptothefieldwidth.
|
ios_base::left |
theoutputisfilledattheendenlargingtheoutputuptothefieldwidth.
|
ios_base::oct |
input/outputintegerinoctalbaseformat.
|
ios_base::right |
theoutputisfilledatthebeginningenlargingtheoutputuptothefieldwidth.
|
ios_base::scientific |
outputfloating-pointvaluesinscientificnotation.
|
ios_base::showbase |
outputintegervaluesprecededbythenumericbase.
|
ios_base::showpoint |
outputfloating-pointvaluesincludingalwaysthedecimalpoint.
|
ios_base::showpos |
outputnon-negativenumericprecededbyaplussign(+).
|
ios_base::skipws |
skipleadingwhitespacesoncertaininputoperations.
|
ios_base::unitbuf |
flushoutputaftereachinsertingoperation.
|
ios_base::uppercase |
outputuppercaselettersreplacingcertainlowercaseletters.
|
Therearealsodefinedthreeotherconstantsthatcanbeusedasmasks:
constant
value
ios_base::adjustfield |
left|right|internal |
ios_base::basefield |
dec|oct|hex |
ios_base::floatfield |
scientific|fixed |
--------------------------------------------------------------------------
用我想要的分隔符来解析一个字符串,以及从流中读取数据
这曾经是一个需要不少麻烦的话题,由于其常用而显得尤其麻烦,但是其实getline可以做得不错:
getline(cin,s,';');
while(s!="quit")
{
cout<<s<<endl;
getline(cin,s,';');
}
简单吧?不过注意,由于这个时候getline只把;作为分隔符,所以你需要用;quit;来结束输入,否则getline会把前后的空格和回车都读入s,当然,这个问题可以在代码里面解决。
同样,对于简单的字符串解析,我们是不大需要动用什么Tokenizer之类的东西了:
#include<iostream>
#include<sstream>
#include<string>
usingnamespacestd;
intmain()
{
strings("hello,world,thisisasentence;andaword,end.");
stringstreamss(s);
for(;;)
{
stringtoken;
getline(ss,token,',');
if(ss.fail())break;
cout<<token<<endl;
}
}
输出:
hello
world
thisisasentence;andaword
end.
很漂亮不是么?不过这么干的缺陷在于,只有一个字符可以作为分隔符。
--------------------------------------------------------------------------
把原本输出到屏幕的东西输出到文件,不用到处去把cout改成fs
#include<iostream>
#include<fstream>
usingnamespacestd;
intmain()
{
ofstreamoutf("out.txt");
streambuf*strm_buf=cout.rdbuf();
cout.rdbuf(outf.rdbuf());
cout<<"writesomethingtofile"<<endl;
cout.rdbuf(strm_buf);//recover
cout<<"displaysomethingonscreen"<<endl;
system("PAUSE");
return0;
}
输出到屏幕的是:
displaysomethingonscreen
输出到文件的是:
writesomethingtofile
也就是说,只要改变ostream的rdbuf,就可以重定向了,但是这招对fstream和stringstream都没用。
--------------------------------------------------------------------------
关于istream_iterator和ostream_iterator
经典的ostream_iterator例子,就是用copy来输出:
#include<iostream>
#include<fstream>
#include<sstream>
#include<algorithm>
#include<vector>
#include<iterator>
usingnamespacestd;
intmain()
{
vector<int>vect;
for(inti=1;i<=9;++i)
vect.push_back(i);
copy(vect.begin(),vect.end(),
ostream_iterator<int>(cout,"")
);
cout<<endl;
ostream_iterator<double>os_iter(cout,"~");
*os_iter=1.0;
os_iter++;
*os_iter=2.0;
*os_iter=3.0;
}
输出:
123456789
1~2~3~
很明显,ostream_iterator的作用就是允许对stream做iterator的操作,从而让算法可以施加于stream之上,这也是STL的精华。与前面的“读取文件”相结合,我们得到了显示一个文件最方便的办法:
copy(istreambuf_iterator<char>(ifs.rdbuf()),
istreambuf_iterator<char>(),
ostreambuf_iterator<char>(cout)
);
同样,如果你用下面的语句,得到的会是没有分隔符的输出:
copy(istream_iterator<char>(ifs),
istream_iterator<char>(),
ostream_iterator<char>(cout)
);
那多半不是你要的结果。如果你硬是想用istream_iterator而不是istreambuf_iterator呢?还是有办法:
copy(istream_iterator<char>(ifs>>noskipws),
istream_iterator<char>(),
ostream_iterator<char>(cout)
);
但是这样不是推荐方法,它的效率比第一种低不少。
如果一个文件temp.txt的内容是下面这样,那么我的这个从文件中把数据读入vector的方法应该会让你印象深刻。
12345234567
8910
程序:
#include<iostream>
#include<fstream>
#include<algorithm>
#include<vector>
#include<iterator>
usingnamespacestd;
intmain()
{
ifstreamifs("temp.txt");
vector<int>vect;
vect.assign(istream_iterator<int>(ifs),
istream_iterator<int>()
);
copy(vect.begin(),vect.end(),ostream_iterator<int>(cout,""));
}
输出:
123452345678910
很酷不是么?判断文件结束、移动文件指针之类的苦工都有istream_iterator代劳了。
-----------------------------------------------------------------------
其它算法配合iterator
计算文件行数:
intline_count=
count(istreambuf_iterator<char>(ifs.rdbuf()),
istreambuf_iterator<char>(),
'/n');
当然确切地说,这是在计算文件中回车符的数量,同理,你也可以计算文件中任何字符的数量,或者某个token的数量:
inttoken_count=
count(istream_iterator<string>(ifs),
istream_iterator<string>(),
"#include");
注意上面计算的是“#include”作为一个token的数量,如果它和其他的字符连起来,是不算数的。
------------------------------------------------------------------------
Manipulator
Manipulator是什么?简单的说,就是一个接受一个stream作为参数,并且返回一个stream的函数,比如上面的unskipws,它的定义是这样的:
inlineios_base&
noskipws(ios_base&__base)
{
__base.unsetf(ios_base::skipws);
return__base;
}
这里它用了更通用的ios_base。知道了这一点,你大概不会对自己写一个manipulator有什么恐惧感了,下面这个无聊的manipulator会忽略stream遇到第一个分号之前所有的输入(包括那个分号):
template<classcharT,classtraits>
inlinestd::basic_istream<charT,traits>&
ignoreToSemicolon(std::basic_istream<charT,traits>&s)
{
s.ignore(std::numeric_limits<int>::max(),s.widen(';'));
returns;
}
不过注意,它不会忽略以后的分号,因为ignore只执行了一次。更通用一点,manipulator也可以接受参数的,下面这个就是 ignoreToSemicolon的通用版本,它接受一个参数,stream会忽略遇到第一个该参数之前的所有输入,写起来稍微麻烦一点:
structIgnoreTo{
charignoreTo;
IgnoreTo(charc):ignoreTo(c)
{}
};
std::istream&operator>>(std::istream&s,constIgnoreTo&manip)
{
s.ignore(std::numeric_limits<int>::max(),s.widen(manip.ignoreTo));
returns;
}
但是用法差不多:
copy(istream_iterator<char>(ifs>>noskipws>>IgnoreTo(';')),
istream_iterator<char>(),
ostream_iterator<char>(cout)
);
其效果跟IgnoreToSemicolon一样。
相关推荐
汇集了来自世界各地的顶尖Visual C++编程高手愿意无偿奉献的得意之作,共计21章206个程序,涉及的方面包括:按钮控件、编辑控件、静态控件、组合框控件、列表视控件、树视控件、工具条控件、状态条控件、其他公共...
VISUAL C++高手指导,成就编程高手
高手只是方法的表象 将方法原则化 完成了这些原则也就成就了手 这是成就c++高手的原则
C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++C++
《C++高手参考手册》是一本专为C++程序员打造的深入学习资源,它涵盖了C++语言的各个方面,旨在帮助读者提升技能至高手水平。"绝对物超所值"的标签意味着这本书的内容丰富且深入,无论是对初学者还是经验丰富的...
visual c++编程高手,详细讲解按钮控件、编辑控件、静态控件、组合框控件、列表视控件、树视控件、工具条控件、状态条控件、其他公共控件、ActiveX控件、对话框、视窗模型、分隔器窗口、位图、剪接板、多媒体、shell...
《Visual C++编程高手》是一本专注于提升C++开发者技能的专业书籍,主要针对Microsoft的Visual C++ 6.0开发环境。此资源包含了代码示例和可能的电子书内容,对于学习和理解C++编程,尤其是使用Visual C++ 6.0进行...
本光盘和图书汇集了来自世界各地的顶尖Visual C++编程高手愿意无偿奉献的得意之作,共计21章206个程序,涉及的方面包括:按钮控件、编辑控件、静态控件、组合框控件、列表视控件、树视控件、工具条控件、状态条控件...
C++Builder 高手进阶 编写弹出广告杀手 (二)系统窗口分析器 设计DBTreeView组件 编写多线程应用程序 动态显示任务栏图标
### 标准C++宝典(C++高手必备) #### 一、标准C++简介 在探讨《标准C++宝典》之前,我们先来了解一下什么是标准C++。C++是一种面向对象的编程语言,由Bjarne Stroustrup于1983年在贝尔实验室开发而成。它是在...
本书及其配套光盘汇集了98年一年间来自世界各地的Visual C++编程好手愿意无偿公开的源程序。其中既有短至几行却非常关键的代码,更有一个类的完整实现,还有非常实用、大型的完整应用程序。无论对于Visual C++新手...
此文件乃txt文档,下载后只需复制到dev-c++新建的cpp文件中编译运行即可
c++小游戏c++小游戏c++小游戏c++小游戏c++小游戏c++小游戏c++小游戏c++小游戏c++小游戏c++小游戏c++小游戏c++小游戏c++小游戏c++小游戏c++小游戏c++小游戏c++小游戏c++小游戏c++小游戏c++小游戏c++小游戏c++小游戏...
零基础学通c++(c++从新手到高手)范磊老师教程txt版 值得放在手机里收藏
本光盘和图书汇集了来自世界各地的顶尖Visual C++编程高手愿意无偿奉献的得意之作,共计21章206个程序,涉及的方面包括:按钮控件、编辑控件、静态控件、组合框控件、列表视控件、树视控件、工具条控件、状态条控件...
本光盘和图书汇集了来自世界各地的顶尖Visual C++编程高手愿意无偿奉献的得意之作,共计21章206个程序,涉及的方面包括:按钮控件、编辑控件、静态控件、组合框控件、列表视控件、树视控件、工具条控件、状态条控件...
本光盘和图书汇集了来自世界各地的顶尖Visual C++编程高手愿意无偿奉献的得意之作,共计21章206个程序,涉及的方面包括:按钮控件、编辑控件、静态控件、组合框控件、列表视控件、树视控件、工具条控件、状态条控件...
《C++编程实例100篇》是一本深入浅出的C++编程教程,它以实践为主导,通过丰富的实例帮助学习者掌握C++语言的基础和核心概念。这本书的每个实例都精心设计,旨在帮助初学者和有经验的开发者巩固和提升C++编程技能。 ...
《Effective Modern C++:改善C++11和C++14的42个具体做法(影印版)(英文版)》中包括以下主题:剖析花括号初始化、noexcept规范、完美转发、智能指针make函数的优缺点;讲解std∷move,std∷forward,rvalue引用和...
【描述】:“这是我们老师做的,各种小游戏,我感觉还不错,所以传上来玩玩。” 这里的“我们老师的”小游戏集合展示了C++编程的实用性和创造性。通过编写游戏,开发者能够锻炼逻辑思维能力,提高程序设计技巧,...