C++primer笔记——第八章【IO库】

【第八章】 IO库

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

IO类型之间的关系:
    类型ifstream和istringstream都继承自istream。因此我们可以像使用istream对象一样来使用ifstream和istringstream对象。
    类型ofstream和ostringstream都继承自ostream。
    
8.1.1 IO对象无拷贝或赋值
    不能拷贝或者对IO对象赋值:
    ofstream out1, out2;
    out1 = out2;                // 错误,不能对流对象赋值
    ofstream print(ofstream);    // 错误,不能初始化ofstream参数
    out2 = print(out2);            // 错误,不能拷贝流对象
    由于不能拷贝IO对象,因此也不能将形参或返回类型设置为流类型。
    进行IO操作的函数通常以引用方式传递和返回流。
    读写一个IO对象会改变其状态,因此传递和返回的引用不能是const的。
    
8.1.2 条件状态
    1、一个流一旦发生错误,其上后续的IO操作都会失败。只有当一个流处于无错状态时,才可以从它读取数据,向它写入数据。
    
    2、由于流可能处于错误状态,因此通常在使用一个流之前检查它是否处于良好状态。
    
练习8.1 编写函数,接受一个istream&参数,返回值类型也是istream&。此函数从给定流中读取数据,直至遇到文件结束标识时停止。将读取的数据打印。完成后,在返回流之前,对流进行复位,使其处于有效状态。
【解析】
#include<iostream>
using namespace std;
istream & fun(istream &in)
{
    int v;
    // 直到遇到文件结束符才停止读取
    while (in >> v, !in.eof())
    {
        if (in.bad())
        {
            throw runtime_error("IO流错误");
        }
        if (in.fail())
        {
            cerr << "数据错误,请重试!" << endl;
            in.clear();
            in.ignore(100, '\n');
            continue;
        }
        cout << v << endl;
    }
    in.clear();
    return in;
}
int main()
{
    cout << "请输入一些整数,按ctrl+z结束" << endl;
    fun(cin);
    system("pause");
    return 0;
}
    
    3、while(cin >> i) 在以下情况下回终止
    1)遇到文件结束符    2)遇到IO流错误        3)读入了无效数据
    
8.1.3 管理输出缓冲
    导致缓冲刷新(即数据真正写到输出设备或文件)的原因:
    1)程序正常结束,作为main函数的return操作的一部分,缓冲刷新被执行
    2)缓冲区满时,需要刷新缓冲,而后新的数据才能继续写入缓冲区
    3)可以使用操纵符如endl来显式刷新缓冲区
    4)在每个输出操作后,我们可以使用操纵符unitbuf设置流的内部状态,来清空缓冲区。
    5)一个输出流可能被关联到另一个流。这种清空下,当读写被关联的流时,关联到的流的缓冲区会被刷新。
    例如,默认情况下,cin和cerr都关联到cout。因此,读cin或写cerr都会导致cout的缓冲区被刷新
    
刷新输出缓冲区:
    已经使用过endl操纵符来完成换行并刷新缓冲区的工作。IO库中海油两个类似的操纵符:flush和ends
    其中,flush刷新缓冲区,但不输出任何额外的字符;ends向缓冲区插入一个空字符,然后刷新缓冲区。
    
unitbuf操纵符:
    如果想在每次输出操作后都刷新缓冲区,我们可以使用unitbuf操纵符。
    它告诉流在接下来的每一次写操作后都进行一次flush操作。
    而nounitbuf操纵符则重置流,使其恢复使用正常的系统管理的缓冲区刷新机制:
    cout<< unitbuf;        // 所有输出操作后都会立即刷新缓冲区
    cout<< nounitbuf;    // 回到正常的缓冲方式
    
关联输入和输出流:
    当一个输入流被关联到一个输出流时,任何试图从输入流读取数据的操作都会先刷新关联的输出流。标准库将cin和cout关联在一起。因此,下面的语句
    cin>>i;
    导致cout的缓冲区刷新
    
    tie有两个重载的版本:
    1)一个版本不带参数,返回指向输出流的指针。如果本对象当前关联到一个输出流,则返回的就是指向这个流的指针,如果对象未关联到流,则返回空指针。
    2)第二个版本接受一个指向ostream的指针,将自己关联到此ostream。即,x.tie(&O)将流x关联到输出流o
    
    既可以将一个istream对象关联到另一个ostream,也可以将一个ostream关联到另一个ostream:
    cin.tie(&out);                // 将cin和cout关联在一起。不过标准库已经将它们关联在一起
    // old_tie指向当前关联到cin的流
    ostream *old_tie = cin.tie(nullptr);    // cin不再与其他流关联
    // 将cin与cerr关联
    cin.tie(&cerr);
    
    每个流同时最多关联到一个流,但多个流可以同时关联到同一个ostream
    
8.2 文件输入输出
    1、头文件fstream定义了三个类型来支持文件IO:
    1)ifstream从一个给定文件读取数据
    2)ofstream向一个给定文件写入数据
    3)fstream可以读写给定文件
    
    2、fstream特有的操作
    1)fstream fstrm;            // 创建一个未绑定的文件流。fstream是头文件fstream中定义的一个类型
    2)fstream fstrm(s);        // 创建一个fstream,并打开名为s的文件。s可以是string类型,也可以是一个指向C风格字符串的指针
    3)fstrm.open(s);            // 打开一个名为s的文件,并将文件与fstrm绑定。s可是一个string类型或者一个指向C风格字符串的指针
    4)fstrm.close();            // 关闭与fstrm绑定的文件。返回void
    5)fstrm.is_open();            // 返回一个bool值,指出与fstrm关联的文件是否打开成功且尚未关闭
    
8.2.1 使用文件流对象
    当我们要读写一个文件时,可以定义一个文件流对象,并将对象与文件关联起来。
    
用fstream代替iostream&
    在要求使用基类型对象的地方,可以用继承类型的对象来代替。
    这意味着,接受一个iostream类型引用(或指针)参数的函数,可以用一个对应的fstream(或sstream)类型来调用。
    
成员函数open和close
    如果调用open失败,failbit会被置位。所以进行open是否成功的检测是一个好习惯
    ofstream out;
    out.open("12.txt");
    if(out)    // 检查open是否成功
    
    一旦open失败,随后的试图使用文件流的操作都会失败。为了将文件流关联到另一个文件,必须首先关闭已经关联的文件。一旦文件成功关闭,则可以使用out对象继续打开新的文件
    如果open成功,则open会设置流的状态,使得good()为true
    
自动构造和析构:
    当一个fstream对象离开其作用域时,与之关联的文件会自动关闭。即当一个fstream对象被销毁时,close会被自动调用
    
练习8.4 以读模式打开一个文件,将其内容读入到一个string的vector中,将每行作为一个独立的元素存于vector中
【解析】
    这里我采用了fstream类型,当然也可以使用ifstream类型(只读)
#include<vector>
#include<string>
#include<iostream>
using namespace std;
#include<fstream>
int main()
{
    fstream input;
    input.open("test.txt");
    vector<string> words;

    if (input)
    {
        string line;
        while (getline(input, line))
        {
            words.push_back(line);
        }
    }
    else
    {
        cout << "error";
    }
    input.close();
    for (auto i : words)
    {
        cout << i << endl;
    }
    system("pause");
    return 0;
}

练习8.5 重写上面的程序,将每个单词作为一个独立的元素进行存储
【解析】
    将while循环的条件改为input >> line即可
    
8.2.2 文件模式
    每个流都有一个关联的文件模式,用来指出如何使用文件。
    1)in            以读方式打开
    2)out            以写方式打开
    3)app            每次写操作前均定位到文件末尾
    4)ate            打开文件后立即定位到文件末尾
    5)trunc        截断文件
    6)binary        以二进制方式进行IO
    无论用那种方式打开文件,都可以指定文件模式,调用open打开文件时可以,用一个文件名初始化流来隐式打开文件时也可以。指定文件模式有如下限制:
    1)只可以对ofstream或fstream对象设定out模式
    2)只可以对ifstream或fstream对象设定in模式
    3)只有当out也被设定时,才可以设定trunc模式
    4)只要trunc没被设定,才可以设定app模式。在app模式下,即使没有显式指定out模式,文件也总是以输出方式被打开
    5)默认情况下,即使我们没有指定trunc,以out模式打开的文件也会被截断。
        为了保留以out模式打开的文件的内容,必须同时指定app模式,这样只会将数据追加写到文件末尾;
        或者同时指定in模式,即打开文件同时进行读写操作。
    6)ate和binary模式可以用于任何类型的文件流对象,且可以与其他任何文件模式组合使用
    默认情况下,与ifstream关联的文件默认以in模式打开;与ofstream关联的文件默认以out模式打开;与fstream关联的文件默认以in和out模式打开
    
以out模式打开文件会丢弃已有数据:
    默认情况下,当我们打开一个ofstream时,文件的内容会被丢弃。
    阻止一个ofstream清空给定文件内容的方法是同时指定app模式:
    即:ofstream app("file", ofstream::out | ofstream::app);
    保留被ofstream打开的文件中已有数据的唯一方法是显式指定app或in模式
    
每次调用open时都会确定文件模式:
    对于一个给定流,每当打开文件时,都可以改变其文件模式。
    ofstream out;    // 未指定文件打开模式
    out.open("file");    // 模式隐含设置为输出和截断
    out.close();        // 关闭out,以便我们将其用于其他文件
    out.open("file1", ofstream::app);    // 模式为输出和追加(append模式)
    out.close();
    
8.3 string流
    sstream头文件定义了三个类型来支持内存IO,这些类型可以向string写入数据,从string读取数据,就像string是一个IO流一样
    1)istringstream从string读取数据
    2)ostringstream向string写入数据
    3)stringstream既可以从string读数据也可以向string写数据
    
    stringstream特有的操作:
    1)sstream strm;        // strm是一个未绑定的stringstream对象。sstream是头文件sstream中定义个一个类型
    2)sstream strm(s);        // strm是一个sstream对象,保存string s的一个拷贝。
    3)strm.str();            // 返回strm所保存的string的拷贝
    4)strm.str(s);            // 将string s拷贝到strm中,返回void


 

猜你喜欢

转载自blog.csdn.net/CSDN_dzh/article/details/81265566
今日推荐