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. 四.GC —三分钟认识JAVA回收机制(Java Garbage Collection)

    这里以jdk1.8做讲解.Jdk1.8的分代去掉了永久代,只分为新生代(有的也译为年轻代)和年老代. 名词解释: 系统吞吐量:用于处理应用程序处理事务的线程数与用于GC的线程数的比. pause ti ...

  2. Node.js 入门:Express + Mongoose 基础使用

    前言 Express 是基于 Node.js 平台的 web 应用开发框架,在学习了 Node.js 的基础知识后,可以使用 Express 框架来搭建一个 web 应用,实现对数据库的增删查改. 数 ...

  3. YARN笔记——技术点汇总

    目录 · 概况 · 原理 · 资源调度器分类 · YARN架构 · ResourceManager · NodeManager · ApplicationMaster · Container · YA ...

  4. ZOJ - 3469 Food Delivery (区间dp)

    When we are focusing on solving problems, we usually prefer to stay in front of computers rather tha ...

  5. hdu 6047 Maximum Sequence(贪心)

    Description Steph is extremely obsessed with "sequence problems" that are usually seen on ...

  6. swipe和swiper的区别

    swipe.js--移动WEB页面内容触摸滑动类库 参考http://www.jiawin.com/swipe-mobile-touch-slider 1.swipe只提供简单轮播切换,底部的圆点颜色 ...

  7. 如何通过binlog获取我们想要的MySql语句?

    前言 MySql的binlog一般用于我们对数据的恢复,以及从数据库对主数据库的复制和更新. 假设此时我们有一个需要查询和读取Mysql最近操作DDL的信息,我们需要怎么处理? 聪明的你可能已经想到了 ...

  8. centos7源码编译安装Ansible详细部署

    一.基础介绍==========================================================================================ansi ...

  9. .net程序实现给机器加域,添加域账号到本地管理员

    以下.net代码中共有两个方法. AddComputerToDomain实现给把本计算机添加到某个域中 AddDomainUserToLocalAdminGroup实现把域中某用户添加到本地管理员 请 ...

  10. NYOJ116 士兵杀敌(二)

    士兵杀敌(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:5   描述 南将军手下有N个士兵,分别编号1到N,这些士兵的杀敌数都是已知的. 小工是南将军手下的军师,南将军经常 ...