`
nathan09
  • 浏览: 155486 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

[转载]高手戏玩c++(2)

 
阅读更多

简单常识——关于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++编程高手

    汇集了来自世界各地的顶尖Visual C++编程高手愿意无偿奉献的得意之作,共计21章206个程序,涉及的方面包括:按钮控件、编辑控件、静态控件、组合框控件、列表视控件、树视控件、工具条控件、状态条控件、其他公共...

    Visual+C+++编程高手

    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++C++C++C++C++C++

    C++高手参考手册,绝对物超所值!!!

    《C++高手参考手册》是一本专为C++程序员打造的深入学习资源,它涵盖了C++语言的各个方面,旨在帮助读者提升技能至高手水平。"绝对物超所值"的标签意味着这本书的内容丰富且深入,无论是对初学者还是经验丰富的...

    visual c++编程高手

    visual c++编程高手,详细讲解按钮控件、编辑控件、静态控件、组合框控件、列表视控件、树视控件、工具条控件、状态条控件、其他公共控件、ActiveX控件、对话框、视窗模型、分隔器窗口、位图、剪接板、多媒体、shell...

    Visual C++编程高手(仅code包,还有电子书)

    《Visual C++编程高手》是一本专注于提升C++开发者技能的专业书籍,主要针对Microsoft的Visual C++ 6.0开发环境。此资源包含了代码示例和可能的电子书内容,对于学习和理解C++编程,尤其是使用Visual C++ 6.0进行...

    Visual C++ 6.0 编程高手.part10

    本光盘和图书汇集了来自世界各地的顶尖Visual C++编程高手愿意无偿奉献的得意之作,共计21章206个程序,涉及的方面包括:按钮控件、编辑控件、静态控件、组合框控件、列表视控件、树视控件、工具条控件、状态条控件...

    C++Builder 高手进阶.chm

    C++Builder 高手进阶 编写弹出广告杀手 (二)系统窗口分析器 设计DBTreeView组件 编写多线程应用程序 动态显示任务栏图标

    标准C++宝典(C++高手必备)

    ### 标准C++宝典(C++高手必备) #### 一、标准C++简介 在探讨《标准C++宝典》之前,我们先来了解一下什么是标准C++。C++是一种面向对象的编程语言,由Bjarne Stroustrup于1983年在贝尔实验室开发而成。它是在...

    Visual C++编程高手(新手老手都适合)

    本书及其配套光盘汇集了98年一年间来自世界各地的Visual C++编程好手愿意无偿公开的源程序。其中既有短至几行却非常关键的代码,更有一个类的完整实现,还有非常实用、大型的完整应用程序。无论对于Visual C++新手...

    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++小游戏...

    零基础学通c++(c++从新手到高手)范磊老师教程txt版

    零基础学通c++(c++从新手到高手)范磊老师教程txt版 值得放在手机里收藏

    Visual C++ 6.0 编程高手.part03

    本光盘和图书汇集了来自世界各地的顶尖Visual C++编程高手愿意无偿奉献的得意之作,共计21章206个程序,涉及的方面包括:按钮控件、编辑控件、静态控件、组合框控件、列表视控件、树视控件、工具条控件、状态条控件...

    Visual C++ 6.0 编程高手.part05

    本光盘和图书汇集了来自世界各地的顶尖Visual C++编程高手愿意无偿奉献的得意之作,共计21章206个程序,涉及的方面包括:按钮控件、编辑控件、静态控件、组合框控件、列表视控件、树视控件、工具条控件、状态条控件...

    Visual C++ 6.0 编程高手.part01.rar

    本光盘和图书汇集了来自世界各地的顶尖Visual C++编程高手愿意无偿奉献的得意之作,共计21章206个程序,涉及的方面包括:按钮控件、编辑控件、静态控件、组合框控件、列表视控件、树视控件、工具条控件、状态条控件...

    C++编程实例100篇

    《C++编程实例100篇》是一本深入浅出的C++编程教程,它以实践为主导,通过丰富的实例帮助学习者掌握C++语言的基础和核心概念。这本书的每个实例都精心设计,旨在帮助初学者和有经验的开发者巩固和提升C++编程技能。 ...

    Effective Modern C++:改善C++11和C++14的42个具体做法(中文版 + 英文版)

    《Effective Modern C++:改善C++11和C++14的42个具体做法(影印版)(英文版)》中包括以下主题:剖析花括号初始化、noexcept规范、完美转发、智能指针make函数的优缺点;讲解std∷move,std∷forward,rvalue引用和...

    c++各种小游戏(我们老师的)

    【描述】:“这是我们老师做的,各种小游戏,我感觉还不错,所以传上来玩玩。” 这里的“我们老师的”小游戏集合展示了C++编程的实用性和创造性。通过编写游戏,开发者能够锻炼逻辑思维能力,提高程序设计技巧,...

Global site tag (gtag.js) - Google Analytics