C++primer第八章 IO库 8.1 IO类

IO库设施

  • istream  (输入流)类型,提供输入操作。
  • ostream (输出流)类型,提供输出操作。
  • cin,—个 istream对象,从标准输入读取数据。
  • cout, 一个ostream对象,向标准输出写入数据。
  • cerr, 一个。stream对象,通常用于输出程序错误消息,写入到标准错误。
  • >>运 算 符 ,用来从一个istream对象读取输入数据。
  • <<运算符,用来向一个stream对象写入输出数据。 
  • getline函数(参见3.3.2节,第 78页),从一个给定的istream读取一行数据, 存入一个给定的string对象中

8.1 IO类

  • iostream定义了用于读写流的基本类型,fstream定义了读写 命名文件的类型,sstream定义了读写内存string对象的类型

  • 为了支持使用宽字符的语言,标准库定义了一组类型和对象来操纵wchar_t类型的 数 据 (参见2.1.1节,第 30页)。宽字符版本的类型和函数的名字以一个w 开始。例如,wcin、wcout和 wcerr是分别对应cin、cout和 cerr的宽字符版对象。宽字符版本的类型和对象与其对应的普通char版本的类型定义在同一个头文件中。例如,头文件f stream 定义了 ifstream 和 wif stream 类型

IO类型间的关系

  • 概念上,设备类型和字符大小都不会影响我们要执行的IO 操作。例如,我们可以用>>读取数据,而不用管是从一个控制台窗口,一个磁盘文件,还是一个string 读取。类似的,我们也不用管读取的字符能存入一个char对象内,还是需要一个wchar_t对象来存储。
  • 标准库使我们能忽略这些不同类型的流之间的差异,这是通过继承机制(inheritance) 实现的。利用模板(参见3.3节,第 87页),我们可以使用具有继承关系的类,而不必了解继承机制如何工作的细节。我们将在第15章和18.3节 (第 710页)介绍C++是如何支持继承机制的。简单地说,继承机制使我们可以声明一个特定的类继承自另一个类。我们通常可以将一个派生类(继承类)对象当作其基类(所继承的类)对象来使用
  • 类 型ifstream和istringstream都继承自istream。因此,我们可以像使用istream对象一样来使用ifstream 和istringstream对象。也就是说,我们是如何使 用cin的,就可以同样地使用这些类型的对象。例如,可以对一个ifstream 或istringstream对 象 调 用getline, 也 可 以 使 用>>从 一 个ifstream 或istringstream对象中读取数据。类似的,类型ostringstream和ofstream都继
    承自ostream 。因此,我们是如何使用cout的,就可以同样地使用这些类型的对象。 
  • 本节剩下部分所介绍的标准库流特性都可以无差别地应用于普通流、文件流和string流,以及char或宽字符流版本

 8.1.1  IO对象无拷贝或赋值

  • 如我们在7.1.3节(第234页)所见,我们不能拷贝或对IO对象赋值
  • ofstream outl,out2;
  • outl=out2;//错误:不能对流对象赋值
  • ofstream print(ofstream);//错误:不能初始化ofstream参数
  • out2=print(out2);//错误:不能拷贝流对象
  • 由于不能拷贝IO对象,因此我们也不能将形参或返回类型设置为流类型(参见6.2.1节,第188页)。进行IO操作的函数通常以引用方式传递和返回流读写一个IO对象会改变其状态,因此传递和返回的引用不能是const的

8.1.2条件状态

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

  • 下面是一个IO错误的例子:int ival;cin >> ival;
  • 如果我们在标准输入上键入Boo,读操作就会失败。代码中的输入运算符期待读取一个int,但却得到了一个字符B。这样,cin会进入错误状态。类似的,如果我们输入一个文件结束标识,cin也会进入错误状态。一个流一旦发生错误,其上后续的IO操作都会失败。只有当一个流处于无错状态时,我们才可以从它读取数据,向它写入数据。由于流可能处于错误状态,因此代码通常应该在使用一个流之前检查它是否处于良好状态。确定一个流对象的状态的最简单的方法是将它当作一个条件来使用:
  • while(cin >> word)//ok:读操作成功...
  • while循环检查>>表达式返回的流的状态。如果输入操作成功,流保持有效状态,则条件为真。

查询流的状态

  • 将流作为条件使用,只能告诉我们流是否有效,而无法告诉我们具体发生了什么。有时我们也需要知道流为什么失败。例如,在键入文件结束标识后我们的应对措施,可能与遇到一个IO设备错误的处理方式是不同的。
  • IO库定义了一个与机器无关的iostate类型,它提供了表达流状态的完整功能。这个类型应作为一个位集合来使用,使用方式与我们在4.8节中(第137页)使用quizl的方式一样。IO库定义了4个iostate类型的const expr值(参见2.4.4节,第58页),表示特定的位模式。这些值用来表示特定类型的IO条件,可以与位运算符(参见4.8节,第137页)一起使用来一次性检测或设置多个标志位。
  • badbit表示系统级错误,如不可恢复的读写错误。通常情况下,一旦badbit被置位,流就无法再使用了。在发生可恢复错误后,failbit被置位,如期望读取数值却读出一个字符等错误。这种问题通常是可以修正的,流还可以继续使用。如果到达文件结束位置,eofbit和failbit都会被置位。goodbit的值为0,表示流未发生错误。如果badbit、failbit和eofbit任一个被置位,则检测流状态的条件会失败
  • 标准库还定义了一组函数来查询这些标志位的状态。操作good在所有错误位均未置位的情况下返回true,而bad、fail和eof则在对应错误位被置位时返回true。此外,在badbit被置位时,fail也会返回true。这意味着,使用good或fail是确定流的总体状态的正确方法。实际上,我们将流当作条件使用的代码就等价于!fail()而eof和bad操作只能表示特定的错误

管理条件状态

  • 流对象的rdstate成员返回一个iostate值,对应流的当前状态。setstate操作将给定条件位置位,表示发生了对应错误clear成员是一个重载的成员(参见6.4节,第206页):它有一个不接受参数的版本,而另一个版本接受一个iostate类型的参数。clear不接受参数的版本清除(复位)所有错误标志位。执行clear()后,调用good会返回true。我们可以这样使用这些成员:
  • //记住cin的当前状态
  • auto old_state=cin.rdstate();//记住cin的当前状态
  • cin.clear();//使cin有效
  • process_input(cin);//使用cin
  • cin.setstate(old_state);//将cin置为原有状态
  • 带参数的clear版本接受一个iostate值,表示流的新状态。为了复位单一的条件状态位,我们首先用rdstate读出当前条件状态,然后用位操作将所需位复位来生成新的状态。例如,下面的代码将failbit和badbit复位,但保持eofbit不变:
  • //复位failbit和badbit,保持其他标志位不变
  • cin.clear(cin.rdstate() & ~cin.failbit & ~cin.badbit);

 

8 .1 .3 管理输出缓冲

  • 每个输出流都管理一个缓冲区,用来保存程序读写的数据。例如,如果执行下面的代码
  • os << "please enter a value: **;
  • 文本串可能立即打印出来,但也有可能被操作系统保存在缓冲区中,随后再打印。有了缓冲机制,操作系统就可以将程序的多个输出操作组合成单一的系统级写操作。由于设备的写操作可能很耗时,允许操作系统将多个输出操作组合为单一的设备写操作可以带来很大的性能提升。缓冲区只有被数据填满,才会刷新缓冲区,将数据写到指定的文件中
  • 导致缓冲刷新(即,数据真正写到输出设备或文件)的原因有很多:
  • 1,程序正常结束,作为main函数的return操作的一部分,缓冲刷新被执行
  • 2,缓冲区满时,需要刷新缓冲,而后新的数据才能继续写入缓冲区。
  • 3,我们可以使用操纵符如endl(参见1.2节,第6页)来显式刷新缓冲区
  • 4,在每个输出操作之后,我们可以用操纵符unitbuf设置流的内部状态,来清空缓冲区。默认情况下,对cerr是设置unitbuf的,因此写到cerr的内容都是立即刷新的。
  • 5,一个输出流可能被关联到另一个流。在这种情况下,当读写被关联的流时,关联到的流的缓冲区会被刷新。例如,默认情况下,cin和cerr都关联到cout。因此,读cin或写cerr都会导致cout的缓冲区被刷新。

刷新输出缓冲区

  • 我们己经使用过操纵符endl,它完成换行并刷新缓冲区的工作。IO库中还有两个类似的操纵符:flush和ends。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有两个重载的版本(参见6.4节,第206页):一个版本不带参数,返回指向输出流的指针。如果本对象当前关联到一个输出流,则返回的就是指向这个流的指针,如果
    对象未关联到流,则返回空指针。
  • tie的第二个版本接受一个指向。stream的指针,将自己关联到此ostreamo即,x.tie(&o)将流x关联到输出流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间的正常关联
  • 在这段代码中,为了将一个给定的流关联到一个新的输出流,我们将新流的指针传递给了tie。为了彻底解开流的关联,我们传递了一个空指针。每个流同时最多关联到一个流,但多个流可以同时关联到同一个ostream。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/446733.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2014年英语一作文partB漫画作文

题目 Write an essay of 160-200 words based on the following drawing.In your essay you should describe the drawing brieflyexplain its intended meaning,give your comments 做题点 1.使用三段式,第一段:图片内容;第二段:图片暗示;第三段:写自己的评论 2.描述图片…

Spring Cloud 系列之 Nacos 配置中心

目录一、Nacos简介二、Nacos安装及配置1、环境准备2、安装包下载&#xff08;1&#xff09;源码方式&#xff08;2&#xff09;发行包方式3、启动Nacos服务4、Nacos数据库配置&#xff08;1&#xff09;MySQL数据源&#xff08;2&#xff09;初始化 MySQL 数据库&#xff08;3&…

C++primer第八章 IO库 8.2 文件输入输出

8.2文件输入输出 头文件fstream定义了三个类型来支持文件IO&#xff1a;ifstream从一个给定文件读取数据&#xff0c;ofstream向一个给定文件写入数据&#xff0c;以及fstream可以读写给定文件。在17.5.3节中&#xff08;第676页&#xff09;我们将介绍如何对同一个文件流既读…

SpringBoot 集成 Nacos

目录一、前言二、Nacos集成1、引入Nacos依赖2、设置Nacos配置3、加载Nacos配置中心配置项4、Nacos集成验证5、Nacos配置中心配置项动态生效Nacos安装详见&#xff1a;Spring Cloud 系列之 Nacos 配置中心 一、前言 上一篇已经讲解了怎样安装安装、启动、配置 Nacos&#xff0c…

C++primer第八章 IO库 8.3string流

8.3string流 sstream头文件定义了三个类型来支持内存IO,这些类型可以向string写入数据,从string读取数据&#xff0c;就像string是一个IO流一样。istringstream从string读取数据&#xff0c;ostringstream向string写入数据&#xff0c;而头文件stringstream既可从string读数据…

英语口语海报演讲--东软

海报 海报上的内容 Nuclear waste water 1.Damage the devastating impact of nuclear radiation on the world 2.Marine life genetically mutated or dead 3.water resources polluted water resources 4.the future of humanity genetic damage/food and environment destr…

C++primer第九章 顺序容器 9.1 顺序容器概述 9.2容器库概览

一个容器就是一些特定类型对象的集合。顺序容器(sequentialcontainer)为程序员提供了控制元素存储和访问顺序的能力。这种顺序不依赖于元素的值&#xff0c;而是与元素加入容器时的位置相对应。与之相对的&#xff0c;我们将在第11章介绍的有序和无序关联容器&#xff0c;则根据…

C++primer第九章 顺序容器 9.3 顺序容器操作

9.3顺序容器操作 顺序容器和关联容器的不同之处在于两者组织元素的方式。这些不同之处直接关系到了元素如何存储、访问、添加以及删除。上一节介绍了所有容器都支持的操作&#xff08;罗列于表9.2&#xff08;第295页&#xff09;&#xff09;。本章剩余部分将介绍顺序容器所特…

C++primer第九章 顺序容器 9.4 vector对象是如何增长的

为了支持快速随机访问&#xff0c;vector将元素连续存储&#xff0c;每个元素紧挨着前一个元素存储。通常情况下&#xff0c;我们不必关心一个标准库类型是如何实现的&#xff0c;而只需关心它如何使用。然而&#xff0c;对于vector和string,其部分实现渗透到了接口中。假定容器…

C++primer第九章 顺序容器 9.5 额外的string操作

除了顺序容器共同的操作之外&#xff0c;string类型还提供了一些额外的操作。这些操作中 的大部分要么是提供string类和C 风格字符数组之间的相互转换,要么是增加了允许我们用下标代替迭代器的版本。标准库string类型定义了大量函数。幸运的是&#xff0c;这些函数使用了重复的…

Zookeeper Mac下安装操作

目录一、下载Zookeeper二、修改配置1、设置启动配置文件2、修改配置三、启动Zookeeper服务命令1、bin目录下执行&#xff08;1&#xff09;启动Zookeeper命令&#xff08;2&#xff09;查看Zookeeper状态命令&#xff08;3&#xff09;停止Zookeeper命令2、配置环境变量执行&am…

2014年考研英语二作文PartB图表题

作文详细解析 题目 Write an essay based on the following chart, in which you should interpret the chart, and give your comments You should write about 150 words on the ANSWER SHEET.(15 points) 注意点 1.图表题在第一段描述图表信息时,一定要写清楚y轴变化…

C++primer第九章 顺序容器 9.6 容器适配器

9.6容器适配器 除了顺序容器外&#xff0c;标准库还定义了三个顺序容器适配器&#xff1a;stack、queue和priority_queue适配器(adaptor)是标准库中的一个通用概念。容器、迭代器和函数<369I都有适配器。本质上&#xff0c;一个适配器是一种机制&#xff0c;能使某种事物的…

SpringBoot Controller接收参数的常用方式

文章目录一、请求路径参数1、PathVariable二、Body参数1、RequestParam2、RequestBody三、请求头参数和Cookie参数1、RequestHeader2、CookieValue一、请求路径参数 1、PathVariable 注解为&#xff1a; org.springframework.web.bind.annotation.PathVariable获取路径参数&…

C++primer第十章 泛型算法 10.1 概述 10.2 初识泛型算法

大多数算法都定义在头文件algorithm中。标准库还在头文件numeric中定义了 一组数值泛型算法一般情况下&#xff0c;这些算法并不直接操作容器&#xff0c;而是遍历由两个迭代器指定的一个元素范围(参见9.2.1节&#xff0c;第296页)来进行操作。通常情况下&#xff0c;算法遍历范…

MySQL Mac安装教程

文章目录一、下载安装包二、安装三、启动MySQL四、环境变量设置一、下载安装包 下载地址&#xff1a;https://downloads.mysql.com/archives/community/ 二、安装 双击安装包&#xff0c;然后一直点继续即可。 三、启动MySQL 打开 系统偏好设置&#xff0c;会发现多了一个…

C++生成指定范围内的随机数

代码 rand&#xff08;&#xff09;% 3 &#xff1b; 3就是范围&#xff0c;代表生成[0,3)之间的随机数 int main(){for (int i 0; i < 20; i) {switch (rand() % 3) {case 0:std::cout << "00" << std::endl;case 1:std::cout << "11&q…

C++primer第十章 泛型算法 10.3 定制操作

10.3定制操作 很多算法都会比较输入序列中的元素。默认情况下&#xff0c;这类算法使用元素类型的&#xff1c;或运算符完成比较。标准库还为这些算法定义了额外的版本&#xff0c;允许我们提供自己定义的操作来代替默认运算符。例如&#xff0c;sort算法默认使用元素类型的&l…

C++primer第十章 泛型算法 10.4 再探迭代器 10.5 泛型算法结构

除了为每个容器定义的迭代器之外&#xff0c;标准库在头文件iterator中还定义了额外几种迭代器。这些迭代器包括以下几种。插入迭代器(insert iterator)&#xff1a;这些迭代器被绑定到一个容器上&#xff0c;可用来向容器插入元素。流迭代器(stream iterator)&#xff1a;这些…

C++primer第十一章 关联容器 11.1使用关联容器 11.2 关联容器概述

关联容器和顺序容器有着根本的不同&#xff1a;关联容器中的元素是按关键字来保存和访问的。与之相对&#xff0c;顺序容器中的元素是按它们在容器中的位置来顺序保存和访问的。虽然关联容器的很多行为与顺序容器相同&#xff0c;但其不同之处反映了关键字的作用关联容器支持高…