《C++primer》第八章读书笔记

《C++Primer 第五版》

​ ——读书随笔集

第八章

8.1 IO类

  • istream,(输入流)类型,提供输入操作
  • ostream ,(输出流)类型,提供输出操作
  • cin,一个istream对象,从标准输入读取数据‘
  • cout,一个ostream对象,向标准输出写入数据
  • cerr,一个ostream对象,通常用于输出程序错误消息,写入到标准错误
  • <<运算符,用来向一个ostream对象中写入输出数据
  • />>运算符,用来从一个istream对象中读取输入数据

8.1.1 IO对象无拷贝和赋值

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

ofstream out1, out2;
out1 = out2; //错误:不能对流对象赋值
ofstream print(ofstream); //错误:不能初始化ofstream对象
out2 = print(out2); //错误,不能拷贝流对象
头文件 类型
iostream istream,wistream从流中读取数据
ostream,wostream向流中写入数据
iostream,wiostream读写流
fstream ifstream,wifstream从文件中读取数据
ofstream,wofstream向文件中写入数据
fstream,wfstream读写文件
sstream istringstream,wistringstream从string中读取数据
ostringstream,wostringstream向string中写入数据
stringstream,wstringstream读写string

为了支持宽类型,标准库定义了一组类型和对象来wchar_t类型的数据。宽字符版本的类型和函数的名字以一个w开始。

本文介绍的标准库流特性都可以无差别地应用于普通流,文件流和string流,以及char或宽字符版本

8.1.2 条件状态

IO类定义了一些函数和标志,可以帮助我们访问和操纵流的条件状态

strm::iostate strm是一种IO类型,iostate是一种机器相关的类型,提供了表达条件状态的完整功能
strm::badbit strm::badbit指流已崩溃
strm::failbit strm::failbit用来指一个IO操作已经失败
strm::eofbit strm::eofbit用来指出流到达了文件结束
strm::goodbit strm::goodbit用来指出流未处于错误状态。此值保证为零
s.eof() 若流s的eofbit置位,则返回true
s.fail() 若流s的failbit或badbit置位,则返回true
s.bad() 若流s的badbit置位,则返回true
s.good() 若流s处于有效状态,则返回true
s.clear(flags) 根据给定的flags标志位,将流中对应条件状态位复位。flags的类型为strm::iostate。返回void
s.setstate(flags) 根据给定的flags标志位,将流中对应条件状态位置位。flags的类型为strm::iostate。返回void
s.rdstate() 返回流s的当前条件状态,返回值类型为strm::iostate
  • 查询流的状态

    badbit表示系统级错误,如不可恢复的错误。通常情况下,一旦badbit被置位,那么流就无法使用了。

    failbit被置位,如期望读取一个数值,结果读取了一个字符。这种问题是可以修复的,流还能继续使用。

    如果到达文件结束位置,eofbit和failbit就会被置位。goodbit的值为0,表示流还未发生错误。

    如果failbit,eofbit和badbit任一个被置位,则检测流状态的条件就会失败。

    标准库还提供了一组函数来查询这些标志位的状态。操作good在所有错误位均未被置位的情况下返回true。

  • 管理条件状态

    clear函数成员是一个重载的成员。他有一个接受参数的版本和一个不接受参数的版本。不接收参数的版本清除所有错误标志位。执行clear()后,调用good会返回true。

    auot old_stat = cin.rdstate(); //返回原来的旧参数
    cin.clear(); //清除参数
    process(cin); // 使用cin
    cin.setstate(old_state); //复原原来的cin
    

    带参数的clear版本接受一个iostate值,表示流的新状态。为了复位单一的状态位,我们可以首先用rdstate读出当前条件状态,然后用位操作将所需位复位来生成新的状态。例如:

    cin.clear(cin.rdstate() & ~cin.failbit & ~cin.badbit) //将failbit和badbit复位,其它位保持不变。
    

8.1.3 管理输出缓冲

每个输出流都有一个缓冲区,用来保存程序读写的数据。

  • 刷新输出缓冲区

    可以使用操纵符endl来完成换行并刷新缓冲区。

    可以使用flush刷新缓冲区,但不输出任何额外的字符。

    可以使用ends向缓冲区插入一个空字符,然后刷新缓冲区。

  • unitbuf操纵符

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

    cout<<unitbuf; // 所有输出操作后立即刷新缓冲区
    cout<< nounitbuf; //回到正常的缓冲方式
    
  • 关联输入和输出流

    当一个输入流被关联到一个输出流时,任何一个试图从输入流读取数据的操作都会先刷新关联的输出流。标准库将cout和cin关联在一起

    cin>>ival; //将刷新cout的缓冲区
    

    交互式系统通常应该关联输入流和输出流。这意味着用户在输入之前,所有输出包括提示信息都应该被输出。

    tie函数有两个重载的版本:一个不带参数(返回指向输出流的指针)。如果本对象当前关联到一个输出流,则返回的就是指向这个流的指针,如果对象未关联到流,则返回空指针。tie的第二个版本接受收一个指向ostream的指针,将自己关联到另一个ostream。

    cin.tie(&cout); //仅仅用来展示
    ostream *old_tie = cin.tie(nullptr);//cin不再与其它流关联
    cin.tie(&cerr); //读取cin会刷新cerr
    cin.tie(&old_tie);//重建cin和cout之间的联系
    

    每个流同时最多关联到一个流,但是多个流可以关联到同一个ostream

8.2 文件的输入输出

头文件fstream定义了三个类型来支持文件IO:ifstream,ofstream,fstream。

这些类型提供的操作与我们之前已经使用过的对象cin和cout一样。它除了继承来自iostream类型的行为以外,fstream中定义的类型还新增了成员来管理与流关联的文件。这些成员只能对ifstream,ofstream,fstream对象调用这些操作,但不能对其他IO类型调用这些操作。

fstream fstrm 创建一个未绑定的文件流
fstream fstrm(s) 创建一个fstream,并打开名为s的文件。
fstream fstream(s,mode) 与前一个构造函数类型,但按指定mode打开文件
fstrm.open(s) 打开名为s的文件,并将文件与fstrm绑定。返回void
fstrm.close() 关闭与fstrm绑定的文件。返回void
fstrm.is_open() 返回一个bool值,指出文件是否打开且尚未关闭。

8.2.1使用文件流对象

ifstream in(file); //构建一个ifstream并打开给定文件
ofstream out; //输出流未关联到任何文件

文件名可以是一个库类型string对象,也可以是C风格字符数组

  • 用fstream代替iostream&

    在要求使用基类型对象的地方,我们可以用继承类型的对象来代替。

  • 成员函数open和close

    ifstream in(ifile); //构建一个ifstream并打开文件
    ofstream out; //输出文件流未与任何文件关联
    out.open(ifile + ".copy"); //打开指定文件
    
  • 自动构造和析构

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

8.2.2 文件模式

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

in 以读方式打开
out 以写方式打开
app 每次写操作前均定位到文件末尾
ate 打开文件后立即定位到文件末尾
trunc 截断文件
binary 以二进制方式进行IO

无论用哪种方式打开文件,我们都可以指定文件模式,调用open打开文件时可以,用一个文件名初始化流来隐式打开文件时也可以。指定文件模式有如下限制∶

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

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

以out模式打开文件会丢失已有数据

默认情况下,当我们打开一个 ofstream 时,文件的内容会被丢弃。阻止一个 ofstream 清空给定文件内容的方法是同时指定 app 模式∶

// 在这几条语句中file1都被截断
ofstream out("file1");                    // 隐含以输出模式打开文件并截断文件                              
ofstream out2("file1", ofstream::out);    // 隐含地截断文件
ofstream out3("file1", ofstream::out | ofstream::trunc);
// 为保留文件内容,我们必须显式指定app模式
ofstream app("file2", ofstream::app);    // 隐含为输出模式
ofstream app2("file2", ofstream::out | ofstream::app);

每次调用open时都会确定文件模式

对于一个给定的流,每次打开文件时,都可以改变文件模式

ofstream out;                            // 未指定文件打开模式
out.open("scratchpad");                  // 模式隐含地设置为输出和截断
out.close();                             // 关闭out,以便用于其他文件
out.open("precious", ofstream::app);     // 模式为输出和追加
out.close();

第一个open调用未显式指定输出模式,文件隐式地以out 模式打开。

通常情况下,out模式意味着同时使用trunc模式。因此,当前目录下名为scratchpad的文件的内容将被清空。

当打开名为 precious 的文件时,我们指定了append模式。文件中已有的数据都得以保留,所有写操作都在文件末尾进行。

8.3 string流

sstream头文件定义了三个类型来支持内存IO,这些类型可以向string写入数据,也可以从string读取数据,就像string是一个IO流一样。

istringstream从string读取数据,ostringstream向string写入数据,而头文件stringstream都可以。下列是sstream特有的成员。

sstream strm strm是一个未绑定的stringstream对象
sstream strm(s) strm是一个sstream对象,保存了string s的一个拷贝
strm.str() 返回strm所保存的string的拷贝,返回的是个string
strm.str(s) 将string s拷贝到strm中。返回void
上一篇:C Primer Plus编程练习(更新中)


下一篇:大熊君大话NodeJS之------Http模块