C++ Primer 学习笔记(第八章)

目录

第八章 IO库

前言

8.1 IO类

8.2 文件输入输出

8.3 string流


第八章 IO库

前言

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

IO库定义了读写内置类型值的操作,此外,一些类如string通常也会定义类似的IO操作,来读写自己的对象。之前已经使用过的IO库设施小结

istream 输入流类型,提供输入操作
ostream 输出流类型,提供输出操作
cin 一个istream对象,从标准输入读取数据
cout 一个ostream对象,向标准输出写入数据
cerr 一个ostream对象,通常用于输出程序错误信息,写入到标准错误
>> 用来从一个istream对象读取输入数据
<< 用来向一个ostream对象写入输出数据
getline函数 从一个给定的istream对象读取一行数据,存入一个给定的string对象中

8.1 IO类

        目前为止,我们使用的IO类型和对象都是操纵char数据的,并且默认情况下,这些对象都是关联到用户的控制台窗口的。而应用程序常常需读写命名文件,且处理string中的字符会很方便。因此,标准库还定义了其他一些IO类型。

表 8.1:IO库类型和头文件
头文件 类型
iostream istream,wistream从流读取数据
ostream,wostream向流写入数据
iostream,wiostream读写流
fstream ifstream,wifstream从文件读取数据
ofstream,wofstream向文件写入数据
fstream,wfstream读写文件
sstream istringstream,wistringstream从string读取数据
ostringstream,wostringstream向string写入数据
stringstream,wstringstream读写string

注意:宽字符版本的类型和函数的名字以一个w开始,例如,wcin、wcout和wcerr。

Ⅰ)IO类型间的关系:由于类的继承机制,设备类型和字符大小不影响所执行的IO操作。例如,用 >> 读取数据,而不用考虑是从一个控制台窗口,一个磁盘文件还是一个string读取。

Ⅱ)IO对象无拷贝或赋值

ofstream out1, out2;
out1 = out2;                // 错误!不能对流对象赋值
ofstream print(ofstream);   // 错误!不能初始化ofstream参数
out2 = print(out2);         // 错误!不能拷贝流对象

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

Ⅲ)流的条件状态

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

在使用流之前,检查它是否处于良好状态。确定一个流对象的状态的最简单的方法是将它当作一个条件来使用

int ival;
cin >> ival;
// 如果在标准输入上键入Boo,读操作就会失败。若输入文件结束标识,cin也会进入错误状态。

while (cin >> word)
    // ok: 读取成功

查询流的状态:有时我们需要知道流为什么失败,IO库定义了一个与机器无关的iostate类型,提供了表达流状态的完整功能。使用eof、fail、bad和good函数来查询流当前的状态。

管理条件状态:使用clear、setstate和rdstate函数管理条件状态。

auto old_state = cin.rdstate();    // 记住cin的当前状态
cin.clear();                       // 使cin有效
process_input(cin);                // 使用cin
cin.setstate(old_state);           // 将cin置为原有状态

Ⅳ)管理输出缓冲:刷新输出缓冲区可以使用endl(再输出一个换行)、flush和ends(再输出一个空字符),如果想在每次输出后都刷新缓冲区,可以使用unitbuf操纵符。当一个输入流被关联到一个输出流时,任何试图从输入流读取数据的操作都会先刷新关联的输出符。

cout << unitbuf;        // 所有输出都刷新缓冲区
cout << nounitbuf;      // 回到正常的缓冲方式

cin >> ival;            // 标准库将cin和cout关联在一起,此语句也会导致cout的缓冲区被刷新

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

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

8.2 文件输入输出

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

表 8.3:fstream特有的操作
fstream fstrm; 创建一个未绑定的文件流。fstream是头文件fstream中定义的一个类型
fstream fstrm(s); 创建一个fstream,并打开名为s的文件。s可以是string类型,或者是一个指向C风格字符串的指针。
fstream fstrm(s, mode); 和上一个相似,但按指定mode打开文件
fstrm.open(s) 打开名为s的文件,并将文件与fstrm绑定
fstrm.close( ) 关闭与fstrm绑定的文件,返回void
fstrm.is_open( ) 返回一个bool值,指出与fstrm关联的文件是否成功打开且尚未关闭

Ⅰ)使用文件流对象

当我们想要读写一个文件时,可以定义一个文件流对象,并将对象与文件关联起来。

ifstream in(ifile);    // 构造一个ifstream并打开给定文件
ofstream out;          // 定义了一个输出流out,输出文件流未关联到任何文件

// 这段代码定义了一个输入流in,它被初始化为从文件读取数据,文件名由string类型的参数ifile指定。

由于继承机制,我们可以用fstream代替iostream& 

ifstream input(argv[1]);                    // 打开销售记录文件
ofstream output(argv[2]);                   // 打开输出文件
Sales_data total;                           // 保存销售总额的变量
if (read(input, total)) {                   // 读取第一条销售记录
    Sales_data trans;                       // 保存下一条销售记录的变量
    while (read(input, trans)) {            // 读取剩余记录
        if (total.isbn() == trans.isbn())   // 检查isbn
            total.combine(trans);           // 更新销售总额
        else {
            print(output, total);           // 打印结果
            total = trans;                  // 处理下一本书
        }
    }
    print(output, total) << endl;           // 打印最后一本书的销售额
} else
    cerr << "No data?!" << endl;            // 文件中无输入数据

 Ⅱ)成员函数open和close

ifstream in(ifile);            // 构筑一个ifstream并打开给定文件
ofstream out;                  // 输出文件流未与任何文件关联
out.open(ifile + ".copy");     // 打开指定文件

if (out)                       // 检查open是否成功,与之前用cin用作条件相似

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

)自动构造和析构:当一个fstream对象被销毁时,close会被自动调用。

)文件模式:每个流都有一个关联的文件模式。

表 8.4:文件模式
in 以读方式打开
out 以写方式打开(会丢弃已有数据)
app 每次写操作前均定位到文件末尾
ate 打开文件后立即定位到文件末尾
trunc 截断文件
binary 以二进制方式进行IO

8.3 string流

表 8.5:stringstream特有的操作
sstream strm; strm是一个未绑定的stringstream对象
sstream strm(s); strm是一个sstream对象,保存string s的一个拷贝
strm.str( ) 返回strm所保存的string的拷贝
strm.str(s) 将string s拷贝到strm中,返回void

 相关参考教程:  C++ 文件和流 | 菜鸟教程 (runoob.com)

                            C++输入输出流 (biancheng.net)

                            C++文件操作 (biancheng.net)

上一篇:C++ primer 中文版(第五版)第一章


下一篇:[C++ Primer Plus] 第四章 复合类型