第八章 IO库

版权声明:转载请注明出处 https://blog.csdn.net/weixin_39918693/article/details/86564593


一、IO类

我们常用的IO对象是关联到用户的控制台窗口的(系统的默认设置,可更改)

iostream中定义了用于读写流的基本类型,fstream中定义了读写命名文件(已存在的文件)的类型,sstream中定义了读写内存中string对象的类型。每个头文件中都有专门用来读写宽字符的类型

概念上,设备类型和字符大小都不会影响我们要执行IO操作。标准库使我们能忽略这些不同类型的流之间的差异,这是通过继承机制实现的。我们通常可以将一个派生类对象当作其基类对象来使用

我们不能拷贝或对IO对象赋值,所以我们不能将形参或返回类型设置为流类型,我们一般将其设置为引用类型,又因为读写一个IO对象会改变其状态,因此该引用不是底层const的

IO操作一个与生俱来的问题是可能发生错误

  • 1、iostate是一种机器相关的类型,提供了表达条件状态的完整功能
  • 2、badbit用来指出流已崩溃,不可恢复的系统级错误
  • 3、failbit用来指出一个IO操作失败,可恢复错误
  • 4、eofbit用来指出流到达了文件结束,可恢复错误
  • 5、goodbit用来指出流未处于错误状态,此值保证为零
  • 6、eof()若流的eofbit置位,则返回true
  • 7、fail()若eofbit或failbit置位,返回true
  • 8、bad()如果badbit置位,返回true
  • 9、good()若流对象处于有效状态,则返回true
  • 10、clear()将流的所有条件状态位复位,将流的状态设置为有效,返回void
  • 11、clear(flags)将指定的状态位复位,返回void
  • 12、setstate(flags)将指定的状态位置位,返回void
  • 13、rdstate()返回流的当前状态,类型是iostate

eofbit不属于fail状态也不属于good状态。亲测有效*

一个流一旦发生错误,其上后续的IO操作都会失败。只有当一个流处于无错状态时,我们才可以从它读取数据或向它写入数据。由于流可能处于错误状态,因此代码通常应该在使用一个流之前检查它是否处于良好状态。确定一个流对象的状态的最简单的方法是将它当作一个条件来使用。如果流的操作成功,则流保持有效状态

IO库定义了4个iostate类型的constexpr值表示特定的位模式。这些值用来表示特定类型的IO条件,可以与位运算符一起用来一次性检测或设置多个标志位。

如果badbit、failbit和eofbit任意一个被置位,则流的状态为失效。good()或fail()是确定流的总体状态的方法,eof()和bad()只能表示特定的错误

每个输出流都管理一个缓冲区,用来保存程序读写的数据。这有利于将IO操作和cpu进行一定程度的分离,可以提高系统的运行速度

导致缓冲区刷新的原因:程序正常结束、缓冲区满的时候、使用操纵符来显式刷新、在一个输出操作之后,我们可以使用unitbuf设置流的内部状态,来清空缓冲区、具有关联关系的流的缓冲区的刷新

cerr是设置了unitbuf的,所以其内容都是立即刷新的

flush刷新缓冲区,但不输出任何额外的字符
ends向缓冲区插入一个空字符,然后刷新缓冲区

设置了unitbuf的流会在接下来的每次操作之后都进行一次flush操作,而nounitbuf则重置流,使其恢复使用正常的系统管理的缓冲区刷新机制

如果程序崩溃,输出缓冲区不会被刷新(确保已经刷新)

标准库将cout和cin、cerr关联到一起,在进行输入或错误输出之前,所有的输出都将被打印出来(交互式系统通常应该关联输入流和输出流)

一般来说都是将istream对象或ostream对象关联到ostream对象上的。这样的话,对前一个对象的操作,会提前刷新后一个ostream对象所管理的缓冲区。与关联有关的操作是由tie函数来实现的,该函数有两个版本,有参数的那个版本返回的好像就是参数的值。我们也可以通过空指针来解关联。每个流最多关联到一个流,但多个流可以同时关联到同一个ostream

以上介绍的绝大多数知识,所有流都是通用的


二、文件输入输出

ifstream从一个给定的文件读取数据,ofstream向一个给定文件写入数据,fstream可以读写给定文件

我们在创建一个文件流对象时,可以进行文件的绑定、文件模式的指定、也可以只是创建一个单一的文件流对象。默认的文件mode依赖于文件流的类型

open(s)打开名为s的文件,并将文件与流对象进行绑定,s可以是string对象也可是指向C风格字符串的指针。返回void

close()关闭与流对象绑定的文件,返回void。好像只是关闭,并未解绑定。进行了解绑定

is_open()返回一个bool值,指出与文件流对象关联的文件是否成功打开且尚未关闭

接受一个iostream类型引用(或指针)参数的函数,可以用一个对应的fstream(或sstream)类型来调用(因为继承的原因)。动态绑定

为了将文件流关联到另一个文件,必须首先关闭已经关联的文件。一旦文件成功关闭,我们可以打开新的文件

当一个文件流对象被销毁时,close会自动被调用(关闭该流所绑定的文件并解除关联)

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

  • 1、in 以读的方式打开
  • 2、out 以写的方式打开
  • 3、app 每次写操作前均被定位到文件末尾
  • 4、ate 打开文件后立即定位到文件末尾
  • 5、trunc 截断文件(既丢弃已有数据)
  • 6、binary 以二进制方式进行IO

无论用哪种方式打开文件,我们都可以指定文件模式(一般就两种吧)

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

每个文件流类型都定义了一个默认的文件模式,当我们未指定文件模式时,就使用默认模式。ifstream默认的是in,oftream默认的是out,fstream默认的是in和out

*理清各种文件模式之间的关系

注意在同时指定两种模式的时候,用|符号连接

建议在每次打开文件时,都要显示设置模式,以防出错


三、string流

sstream头文件定义了三个类型来支持内存IO。istringstream从string读取数据,ostringstream向string写入数据,stringstream可读可写

这三种类型定义的构造函数,可以将在对象中保存一个string的拷贝(你懂的)

str()函数

最后三种类型,实际使用一次就会了


四、IO库再探

除了条件状态外,每个iostream对象还维护一个格式状态来控制IO如何格式化的细节

流的格式状态*

标准库定义了一组操纵符来修改流的格式状态,一个操纵符是一个函数或一个对象,会影响流的状态,并能用作输入或输出运算符的运算对象。类似输入和输出运算符,操纵符也返回它所处理的流对象,因此我们可以在一条语句中组合操纵符和数据(在同一条语句中使用,没问题)

*这里我需要一个例子

操纵符用于两大类输出控制:控制数值的输出形式以及控制补白的数量和位置。大多数改变格式状态的操纵符都是设置/复原成对的;一个操纵符用来将格式状态设置为一个新的值,而另一个用来将其复原,恢复为正常的默认格式

当操纵符改变流的格式状态时,通常改变后的状态对所有后续IO操作都生效。通常最好在不再需要特殊格式时尽快将流恢复到默认状态

控制布尔值的格式、指定整型值的进制、在输出中显式标出进制、控制浮点数格式(打印精度、指定浮点记数法、是否打印小数点)、输出补白(精细的格式控制)、控制输入格式(是否忽略空白)

输出补白操纵符:

  • 1、setw:指定下一个数字或字符串值的最小空间(读或写)
  • 2、left:表示左对齐输出
  • 3、right:表示右对齐输出,右对齐是默认格式
  • 4、internal:控制负数的符号的位置,它左对齐符号,右对齐值,用空格填满中间的空间
  • 5、setfill:允许使用一个字符代替默认的空格来补白输出

setw和endl一样,不改变输出流的内部状态。它只决定下一个输出的大小

流对象的格式状态应该不属于其内部状态

setbase(b)将整数输出为b进制

操作符hex、oct和dec只影响整型运算对象,浮点值的输出形式不受影响

标准库在打印浮点数时,会自动选择一种可读性更好的格式(在用户未显示指定的情况下)

操纵符setprecision和其他接受参数的操纵符都定义在头文件iomanip中

注意指定精度的操纵符和IO对象的成员函数precision在使用上的区别

那些指定浮点数输出格式(记数法)的操纵符会改变流的默认精度的含义(你懂的)

在使用scientific或fixed的时候,我们可以进行按列打印(你懂的,但是效果好像并不好)

操纵符:boolalpha、noboolalpha、hex、oct、dec、showbase、noshowbase、uppercase、nouppercase、showpoint、noshowpoint、showpos、noshowpos、left、right、internal、fixed、scientific、hexfloat、defaultfloat、unitbuf、nounitbuf、skipws、noskipws、flush、ends、endl

默认情况下,输入运算符会忽略空白符(空格符、制表符、换行符、换纸符和回车符)

标准库还提供了一组低层操作,支持未格式化IO,这些操作允许我们将一个流当作一个无解释的字节序列来处理(低层函数容易出错,建议少用),用到时再研究。

*未格式化IO和C语言的I/O模型很像

各种流都支持对流中数据的随机访问,用到时再研究

到底什么是流:

猜你喜欢

转载自blog.csdn.net/weixin_39918693/article/details/86564593