IO类

  C++语言不直接处理出入输出,而是通过一族定义在标准库中的类型来处理IO。这些类型支持从设备读取数据、向设备写入数据的IO操作,设备可以是文件控制台窗口 等。还有一些类型允许内存IO ,即从string读取数据,向string写入数据。常见IO库设施如下:

  • istream(输入流)类型,提供输入操作。
  • ostream(输出流)类型,提供输出操作。
  • cin,一个istream对象,从标准输入读取 数据。
  • cout,一个ostream对象,想标准输出写入 数据。
  • cerr, 一个ostream对象,通常用于输出程序错误信息,写入 到标注错误。
  • > > 运算符,用来从一个istream对象读取输入数据
  • < < 运算符,用来从一个ostream对象写入输出数据
  • getline函数,从一个给定的istream读取一行数据存入一个给定的string对象中(遇到换行符结束)。

  IO库类型的头文件:

  IO类型间的关系:

  1、IO对象无拷贝或赋值:

// 我们不能拷贝或对IO对象赋值
ofstream out1,out2;
out1 = out2; //错误:不能对流对象赋值
ofstream print(ofstream); //错误:不能初始化ofsteram参数
out2 = print(out2); //错误:不能拷贝流对象

  由于不能拷贝IO对象,因此我们也不能将形参或返回类型设置为流类型。进行IO操作的函数通常以引用方式传递和返回流。读写一个IO对象会改变其状态,因此传递和返回的引用不能是const的。

  2、IO库条件状态: IO操作的一个与生俱来的问题是可能发生错误,一些错误是可恢复的,而其他错误则发生在系统深处,已经超出了应用程序可以修正的范围。因此,IO类定义了一些函数和标志,可以帮助我们访问和操纵流的条件状态。



  注意: 一个流一旦发生错误,其上后续的IO操作都会失败。

  确定一个流对象的状态的最简单的方法是将它作为一个条件来使用:

while(cin>>word){
// ok:读操作成功....
}

  查询流的状态: 将流作为条件使用,只能告诉我们流是否有效,而无法告诉我们具体发生了什么。IO库定义了一个iostate 类型,它提供了表达流状态的完整功能。这个类型应作为一个位集合来使用,即通过位运算来使用。IO库定义了4个iostate类型的constexpr 值,表示特定的位模式。这些值用来表示特定类型的IO条件,可以与位运算符一起使用来一次性检测或设置多个标志位。

  管理条件状态: 流对象的rdstate 成员返回一个iostate 值(读取当前条件状态),对应流的当前状态。setstate 操作将给定条件位置位,表示发生了对应错误。clear成员是一个重载的成员,它有一个不接受参数的版本(复位所有错误标志位),而另一个版本接受一个iostate类型的参数。

// 机主cin的当前状态
auto old_state = cin.rdstate(); //记住cin的当前状态
cin.clear(); //使cin有效
process_input(cin); //使用cin
cin,setstate(old_state); //将cin置为原有状态 //复位failbit和badbit,保持其他标志位不变
cin.clear(cin.rdstate() & ~cin.failbit & ~cin.badbit);

  3、管理输出缓冲: 每个输出流 都管理一个缓冲区 ,用来保存程序读写的数据。导致缓冲刷新(即数据真正写到输出设备或文件)的原因有很多:

  • 程序正常结束,作为main函数的return操作的一部分,缓冲刷新被执行。
  • 缓冲区满时,需要刷新缓冲,而后新的数据才能继续写入缓冲区。
  • 我们可以使用操纵符endl、flush、ends 来显示刷新缓冲区。
  • 在每个输出操作之后,我们可以用操纵符unitbuf 设置流的内部状态,来清空缓冲区。默认情况下,对cerr是设置unitbuf的,因此写到cerr的内容都是立即刷新的。
  • 一个输出流可能被关联 到另一个流。在这种情况下,当读写被关联的流时,关联到的流的缓冲区会被刷新。默认情况下,cin和cerr都被关联到cout,因此读cin或写cerr都会导致cout的缓冲区被刷新。

  刷新输出缓冲区: 除了常见的endl外,IO库还有两个类似的操纵符:flushends 。flush刷新缓冲区,但不输出任何额外的字符;ends向缓冲区插入一个空字符,然后刷新缓冲区:

cout<<"hi!"<<endl;      //输出hi和一个换行,然后刷新缓冲区
cout<<"hi!"<<flush; //输出hi不附加任何额外字符,然后刷新缓冲区
cout<<"hi!"<<ends; //输出hi和一个空字符,然后刷新缓冲区

  unitbuf操纵符: 如果想在每次输出操作后都刷新缓冲区,我们可以使用unitbuf操纵符。它告诉流在接下来的每次写操作之后都进行一次flush 操作。而nounitbuf 操纵符则重置流,是其恢复使用正常的系统管理的缓冲区刷新机制:

cout<<unitbuf;                // 所有输出操作后会立即刷新缓冲区
// 任何输出都立即刷新,无缓冲
cout<<nounitbuf; // 回到正常的缓冲方式

  警告: 如果程序崩溃,输出缓冲区是不会被刷新的。

  关联输入和输出流: 当一个输入流被关联到一个输出流时,任何试图从输入流 读取数据的操作都会先刷新关联的输出流 。标准库将cout和cin关联在一起,因此语句cin> > ival; ,将会导致cout的缓冲区被刷新。交互式系统通常应该关联输入流和输出流。这意味着所有输出,包括用户提示信息,都会在读操作之前被打印出来。

  用于关联流的函数主要是tie函数 ,tie有两个重载的版本:一个版本不带参数,返回指向输出流的指针 ,如果本对象当前关联到一个输出流,则返回的就是指向这个流的指针,如果未关联到流,则返回空指针;**tie的第二个版本接受一个指向ostream的指针,将自己关联到此ostream,即x.tie(& o)将流关联到输出流o。

  我们既可以将一个istream 对象关联到另一个ostream ,也可以将一个ostream关联到另一个ostream

cin.tie(&cout)     //仅仅是用来展示:标准库cin和cout关联在一起
//old_tie指向当前关联到cin的流(如果有的话)
ostream *old_tie = cin.tie(nullptr); //cin不再与其他流关联
//将cin与cerr关联;这不是一个好主意,因为cin应该关联到cout
cin.tie(&cerr); //读取cin会刷新cerr而不是cout
cin.tie(old_tie); //重建cin和cout间的正常关联

  注意: 每个流同时最多关联到一个流,但多个流可以同时关联到同一个ostream。

文件输入输出

  1、fstream: 除了继承自iostream类型的行为之外,fstream中定义的类型还增加了一些新的成员来管理与流关联的文件:

  2、使用文件流对象: 如果我们定义了一个空文件流对象,可以随后调用open来将它与文件关联起来:

ifstream in(ifile);     //构筑一个ifstream并打开给定文件
ofstream out; //输出文件流未与任何文件相关联
out.open(ifile + ".copy"); //打开指定文件 //如果调用open失败,failbit会被置位。
//因为调用open可能失败,进行open是否成功的检测通常是一个好习惯
if(out) //检查open是否成功
//open成功,我们可以使用文件了

  一旦一个文件流已经打开,它就保持与对应文件的关联。实际上,对一个已经打开的文件流调用open会失败,并且会导致failbit被置位,随后的试图使用文件流的操作都会失败。为了将文件流关联到另外一个文件,必须首先关闭已经关联的文件:

in.close();            //关闭文件
in.open(ifile+"2"); //打开另一个文件

  注意: 当一个fstream对象被销毁时,close会自动被调用。

  3、文件模式: 每个流都有一个关联的文件模式,用来指出如何使用文件。

  指定文件模式有如下限制:

  • 只可以对ofstream或fstream对象设定out模式。
  • 只可以对ifstream或fstream对象设定in模式。
  • 只有当out也被设定时才可设定trunc 模式。
  • 只要trunc 没被设定,就可以设定app模式。在app 模式下,即使没有显示指定out 模式,文件也总是以输出方式被打开。
  • 默认情况下,即使我们没有指定trunc ,以out 模式打开的文件也会被截断。为了保留以out 模式打开的文件的内容,我们必须同时指定app 模式,这样只会将数据追加写到文件末尾;或者同时指定in 模式,即打开文件同时进行读写操作。
  • atebinary 模式可用于任何类型的文件流对象,且可以与其他任何文件模式组合使用。

  注意: 每个文件流类型都定义了一个默认的文件模式,当我们未指定文件模式时,就使用此默认模式。与ifstream关联的文件默认以in模式打开;与ofstream关联的文件默认以out模式打开;与fstream关联的文件默认以in和out模式打开。

string 流

  1、sstream: 除了自iostream继承得来的的操作,sstream中定义的类型还增加了一些成员来管理与流相关联的string。

  2、使用istringstream: 当我们的某些工作是对整行文本 进行处理,而其他一些工作是处理行内的单个单词 时,通常可以使用istringstream:

//假如要处理如下数据,个人信息(名字,手机号码)
morgan 2015552368 8625550123
drew 9735550130
lee 6095550132 2015550175 8005550000 struct Personlnfo {
string name;
vector <string> phones;
} string line, word ; // 分别保存未自输入的一行和单饲
vector <PersonInfo> people ; // 保存来自输入的所有记录
// 运行从输入读取数据, 直至cin遇到文件尾(或其他错误)
while (getline(cin , line )){
PersonInfoinfo; // 创建一个保存此记录数据的对象
istringstream record(line) ; // 将记录绑定到刚读入的行
record >> info.name ; // 读取名字
while (record >> word) // 读取电话号码
info.phones . push_back(word); // 保持它们
people.push_back(info); // 将此记录追加到pe o ple 末尾
}

  3、使用ostringstream: 当我们逐步构造输出 ,希望最后一起打印 时,ostringstream是很有用的。比如,对上述的例子,我们可能想要逐个验证电话号码并改变其格式。如果所有号码都是有效的,我们希望输出一个新的文件,包含改变格式后的号码。对于那些无效的号码,我们不会将它们输出到新文件中,而是打印一条包含人名和无效号码的错误信息。

for(const auto &entry : people){    //对people中每一项
ostringstream formatted,badNums; //每个循环创建的对象
for(const auto &nums : entry.phone){
if(!valid(nums)){
badNums<<" "<<nums; //将数的字符串形式存入badNums
}
else{
//将格式化的字符串“写入”formatted
formatted<<" "<<format(nums);
}
}
if(badNums.str().empty()) //没有错误的数
os<<entry.name<<" "<<formatted.str()<<endl;
else //否者,打印名字和错误的数
cerr<<"input error"<<entry.name
<<"incalid numbers"<<badNum.str()<<endl;
}

IO库的更多相关文章

  1. [APUE]标准IO库(下)

    一.标准IO的效率 对比以下四个程序的用户CPU.系统CPU与时钟时间对比 程序1:系统IO 程序2:标准IO getc版本 程序3:标准IO fgets版本 结果: [注:该表截取自APUE,上表中 ...

  2. [APUE]标准IO库(上)

    一.流和FILE对象 系统IO都是针对文件描述符,当打开一个文件时,即返回一个文件描述符,然后用该文件描述符来进行下面的操作,而对于标准IO库,它们的操作则是围绕流(stream)进行的. 当打开一个 ...

  3. 文件IO函数和标准IO库的区别

    摘自 http://blog.chinaunix.net/uid-26565142-id-3051729.html 1,文件IO函数,在Unix中,有如下5个:open,read,write,lsee ...

  4. 【转载】C++ IO库

    本篇随笔为转载,原贴地址:<C++ Primer>第8章 IO库 学习笔记. 1.IO类 #include <iostream> istream//从流中读取数据 ostrea ...

  5. 从Decorator,Adapter模式看Java的IO库

    我想任何一本介绍模式的书在讲到Decorator模式的时候不能不提到它的实际应用--在Java/IO库里面的应用,<<Java与模式>>这本书也不例外,有点不一样的是,这本书在 ...

  6. C++ Primer 读书笔记: 第8章 标准IO库

    第8章 标准IO库 8.1 面向对象的标准库 1. IO类型在三个独立的头文件中定义:iostream定义读写控制窗口的类型,fstream定义读写已命名文件的类型,而sstream所定义的类型则用于 ...

  7. 标准模板库——IO库

    IO库设施: . istream(输入流)类型,提供输入操作. . ostream(输出流)类型,提供输出操作. . cin,一个istream对象,从标准输入读取数据. . cout,一个ostre ...

  8. 高级UNIX环境编程5 标准IO库

    标准IO库都围绕流进进行的 <stdio.h><wchar.h> memccpy 一般用汇编写的 ftell/fseek/ftello/fseeko/fgetpos/fsetp ...

  9. 第 8 章 IO库

    第 8 章 IO库 标签: C++Primer 学习记录 IO库 第 8 章 IO库 8.1 IO类 8.2 文件输入输出 8.1 string流 8.1 IO类 IO对象无拷贝或赋值,因此不能将形参 ...

随机推荐

  1. webpack打包编译时,不识别src目录以外的js或css

    前端的dva项目开发时,遇到个很郁闷的问题,用es6的语法简单的export一个变量出来,在其他js中import使用,结果就报错了.   export写法如下: const enUS = { acc ...

  2. HDOJ2012-素数判定

    Problem Description 对于表达式n^2+n+41,当n在(x,y)范围内取整数值时(包括x,y)(-39<=x<y<=50),判定该表达式的值是否都为素数.   I ...

  3. Java中的clone()----深复制,浅复制

    这篇文章主要介绍了Java中对象的深复制(深克隆)和浅复制(浅克隆) ,需要的朋友可以参考下 1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他 ...

  4. 移动端和pc端事件绑定方式以及取消浏览器默认样式和取消冒泡

    ### 两种绑定方式 (DOM0)1.obj.onclick = fn; (DOM2)2. ie:obj.attachEvent(事件名称,事件函数); 1.没有捕获(非标准的ie 标准的ie底下有 ...

  5. 一次浴火重生的MySQL优化(EXPLAIN命令详解)

    一直对SQL优化的技能心存无限的向往,之前面试的时候有很多面试官都会来一句,你会优化吗?我说我不太会,这时可能很多人就会有点儿说法了,比如会说不要使用通配符*去检索表.给常常使用的列建立索引.还有创建 ...

  6. storm从入门到放弃(二),任务分配过程-核心机密

    背景:目前就职于国内最大的IT咨询公司,恰巧又是毕业季,所在部门招了100多个应届毕业生,本人要跟部门新人进行为期一个月的大数据入职培训,特此将整理的文档分享出来. 原文和作者一起讨论:http:// ...

  7. 枪战Maf[POI2008]

    题目描述 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开枪.因此,对于不同的开枪顺序,最后死的人也不同. 输入 输入n人 ...

  8. 使用Nginx搭建本地流媒体服务器

    Mac搭建nginx+rtmp服务器 1.打开终端,查看是否已经安装Homebrew,直接输入命令 man brew 如果Mac已经安装了, 会显示一些命令的帮助信息. 此时输入Q退出即可, 直接进入 ...

  9. SpringBoot启动流程解析

    写在前面: 由于该系统是底层系统,以微服务形式对外暴露dubbo服务,所以本流程中SpringBoot不基于jetty或者tomcat等容器启动方式发布服务,而是以执行程序方式启动来发布(参考下图ke ...

  10. C#设计模式(2)-简单工厂模式

    引言 上一遍中介绍了设计模式中的单例模式-C#设计模式(1)-单例模式,本篇将介绍简单工厂模式,也是比较容易理解的一种模式: 简单工厂模式简介 什么是简单工厂模式? 定义一个工厂类,它可以根据参数的不 ...