• Tips for C++ Primer Chapter 8 IO库


    第8章 IO库

    IO类

    IO库类型和头文件

    头文件:类

    iostream(控制台的IO):istream ostream iostream

    fstream(命名文件的IO):ifstream ofstream fstream

    sstream(内存string对象的IO):istringstream ostringstream stringstream

    PS:

    ifstream、istringstream继承自istream;

    ofstream、ostringstream继承自ostream;

    通常可以将一个派生类对象当作其基类对象来使用,例如可以对ifstream对象使用IO运算符(>>和<<)或getline等。

    IO对象无拷贝和赋值

    由于不能拷贝IO对象,因此不能将形参或返回类型设置为流类型;

    进行IO操作的函数通常以引用的方式传递和返回流;

    读写一个IO对象会改变其状态,因此传递和返回的引用不能是const的

    条件状态

    IO类定义了一些函数和标志,以访问和操纵流的条件状态(condition state)

    以下strm表示某种IO类型(istream等),s是某个流对象

    strm::iostate   iostate是一种机器相关的类型,提供了表达条件状态的完整功能

    strm::badbit   用来指出流已崩溃

    strm::failbit   用来指出一个IO操作失败

    strm::eofbit   用来指出流达到了文件结束

    strm::goodbit   用来指出流未处于错误状态(此值保证为0)

    s.eof()   若流s的eofbit置位,则返回true

    s.bad()   若流s的badbit置位,则返回true

    s.good()   若流s处于有效状态,则返回true

    s.clear()   将流s中所有条件状态位复位,将流的状态设置为有效(goodbit也复位了);返回void

    s.clear(flags)   根据给定的flags标志位,将流s中对应条件状态位复位;flags的类型为strm::iostate;返回void

    s.setstate(flags)   根据给定的flags标志位,将流s中对应条件状态位置位;flags的类型为strm::iostate;返回void

    s.rdstate()   返回流s的当前条件状态,返回值类型为strm::iostate

    流的条件状态位

    badbit表示系统级错误,如不可恢复的读写错误。一旦badbit被置位流就无法再使用了;

    当badbit被置位时,或者在发生可恢复错误后,failbit会被置位,如期望读取数值却读到一个字符等错误。这种错误可以修正,流还可以继续使用;

    如果达到文件结束位置,eofbit和failbit都被置位;

    当流未发生错误,goodbit保持为0

    如果badbit、failbit、eofbit任一被置位,则检测流状态的条件会失败;

      例如 while(cin>>val) 在读到文件结束时终止循环。

    流的条件状态查询函数

    所有错误位均未置位时,good返回true(注意:此时goodbit为0而不是1);

    bad、fail、eof在特定的对应错误位被置位时返回true(注意:badbit或eofbit被置位时,failbit也会被置位,所以fail也会返回true);

    可见:good或fail是确定流的总体状态的方法。

      例如

      实际上 while(cin>>val)

      就等价于 while(cin>>val && cin.good())

      或 while(cin>>val && !cin.fail())

    管理输出缓冲

    每个输出流都管理一个缓冲区;

    由于设备的写操作可能很耗时,允许操作系统将多个输出操作暂存在缓冲区,然后组合为单一的设备写操作,可以带来很大的性能提升

    缓冲区刷新即:数据真正写到输出设备或文件

    导致缓冲区刷新的原因:

      程序正常结束;(实际上,缓冲刷新是main函数return操作的一部分;程序异常终止时输出缓冲区不会被刷新)

      缓冲区满;

      使用操纵符endl显式刷新缓冲区;

      写到cerr;(在每个输出操作之后,可以用操纵符unitbuf设置流的内部状态,来清空缓冲区;而默认情况下,对流对象cerr是设置unitbuf的,因此写到cerr的内容都是立即刷新的)

      一个输出流被关联到了另一个流的情况;(例如,默认情况下,cin和cerr都关联到cout,因此,读cin写cerr都会导致cout的缓冲区被刷新)

    刷新输出缓冲区

    以下操纵符需出现在某个输出操作之后。(cout、cerr等)

    endl:换行并刷新缓冲区

    flush:仅刷新缓冲区

    ends:向缓冲区插入一个空格符,再刷新缓冲区

    unitbuf操纵符

    如果想在每次输出操作后系统都自动刷新缓冲区,可以使用unitbuf操纵符;

    unitbuf告诉流在接下来的每次写操作之后都自动进行一次flush操作。

      cout << unitbuf;

      cout << nounitbuf; //回到正常的缓冲方式

    关联输入和输出流

    当一个输入流被关联到一个输出流时,使用该输入流的操作时会先刷新关联的输出流

    标准库将cin与cout关联在一起。

    tie函数

    tie函数有两个重载的版本:

    一个版本不带参数返回指向输出流的指针。如果本对象当前关联到一个输出流,则返回指向该输出流的指针;如果本对象未关联到流,则返回空指针

    另一个版本接受一个指向ostream的指针,将自己关联到此ostream

    例如:

      ostream* old_tie = cin.tie(); //old_tie指向当前关联到cin的流(系统默认是cout)

      cin.tie(&cerr); //将cin与cerr关联

      cin.tie(nullptr); //解除cin与任何流的关联

      cin.tie(old_tie); //重建cin与cout的关联

    PS:

    可以将一个istream关联到一个ostream,也可以将一个ostream关联到另一个ostream;

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

    文件输入输出

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

      ifstream:读文件

      ofstream:写文件

      fstream:读写文件(将在第17章讨论)

    除了继承自iostream类型的>>、<<、getline等行为之外,fstream中定义的类型有其特有的管理与流关联的文件的成员。

    fstream特有的操作:

    fstream fs   创建一个未绑定的文件流;fstream是头文件fstream中定义的一种类型

    fstream fs(s)   创建一个fstream,并打开(此时open会自动被调用)名为s的文件;s可以是string类型或者指向C风格字符串的指针(C++11之前只允许C风格的字符数组);这些构造函数数都是explicit(第7章)的;默认的文件模式mode依赖于fstream的类型

    fstream fs(s, mode)   与前一个构造函数类似,但按指定mode打开文件

    fs.open(s)   打开名为s的文件,并将文件与fs绑定;默认的文件mode依赖于fstream的类型;返回void

    fs.close()   关闭与fs绑定的文件;返回void

    fs.is_open()   返回bool值;指出与fs关联的文件是否成功打开尚且未关闭

    用fstream代替iostream&

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

    这意味着,接受一个iostream类型引用(或指针)参数的函数,可以用一个对应的fstream(或sstream)类型来调用;

    例如,如果有一个函数接受一个ostream&参数,调用这个函数时,可以传给它一个ofstream对象;(isstream&和ifstream也类似)

    成员函数open和close

    如果调用open失败,failbit会被置位;

    fs.open(s);

    if(fs) //如果open失败,则条件为假

    对一个已经打开的文件流调用open会失败,并导致failbit被置位,随后的文件流操作也都会失败;为了将文件流关联到另一个文件,必须首先关闭已关联的文件。

    fs.close();

    若open成功,则open会设置流的状态,使得good()为true。

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

    文件模式(file mode)

    in   读

    out   写

    app   每次写操作前均定位到文件尾

    ate   打开文件后立即定位到文件尾

    trunc   截断文件

    binary   以二进制方式进行IO

    文件模式规则:

    (1)只可对ofstream或fstream对象设定out模式;

    (2)只可对ifstream或fstream对象设定in模式;

    (3)只有当out被设定时才可设定trunc模式;

    (4)只要trunc未被设定,就可以设定app模式;在app模式下,即使没有显式设定out,文件也总是以输出方式被打开;

    (5)默认情况下,即使未设定trunc,以out模式打开的文件也会被截断;为了保留以out模式打开的文件内容,必须同时指定app模式,这样就会将数据追加到文件尾;或者同时指定in模式,同时进行读写操作(第17章)

    (6)ate和binary模式可用于任何类型的文件流对象,且可与其它任何文件模式组合使用;

    当未显式指定文件模式时,各文件流类型的默认模式

    ifstream:in

    ofstream:out

    fstream:in和out

    一些例子:

    ofstream out(s1); //默认为out模式,文件被截断

    ofstream out2(s1, ofstream::out); //显式指定out,会隐式地截断文件(参考“文件模式规则”:第5条)

    ofstream out3(s1, ofstream::out | ofstream::trunc); //显式截断文件(只有out也被设定,trunc才能被设定;参考“文件模式规则”:第3条

    ofstream app(s2,ofstream::app); //隐式地设定了out

    ofstream app2(s2,ofstream::out | ofstream::app); //与上一条等价

    PS:以上是在初始化流并隐式打开文件时指定文件模式,此外在使用open打开文件时也同样可以指定文件模式。

    string流

    sstream头文件定义了三个类型来支持内存IO:

    istringstream:从string读取数据

    ostringstream:向string写入数据

    stringstream:可从string读取数据,或向string写入数据

    除了继承自iostream头文件的>>、<<、getline等操作,sstream头文件定义的类有其特有操作:

    sstream st   st是一个未绑定的stringstream对象;sstream是头文件sstream中定义的某个类型

    sstream st(s)   st是一个sstream对象,保存string s的一个拷贝;此构造函数时explicit(第7章)

    st.str()   返回st所保存的string的拷贝

    st.str(s)   将string s拷贝到st中;返回void

    使用istringstream

    例子:

    string line, word;
    while(getline(cin, line)) //读取一行
    {
        istringstream iss(line); //将string流iss绑定到读入的一行line(流对象iss中存有line的一个拷贝)
        while(iss>>word) //使用输入运算符从iss流中依次读取各个字符串
            cout<<word<<endl;
    }

    问题:若将istringstream对象定义在循坏之外程序还能完成之前的功能吗?

    string line, word;
    istringstream iss;
    while(getline(cin, line))
    {
        iss.str(line); //调用str函数将流iss绑定到line(流对象iss中存有line的一个拷贝)
        while(iss>>word)
            cout<<word<<endl;
        //iss.clear();
    }

    不能。程序只会成功读取并处理文件中的第一行就终止了。

    原因:当string流中的数据全部读出后,同样会触发“文件结束”信号,此时流iss不在有效了。

    改正:可在某次使用完流之后调用clear函数使所有条件状态位复位,使其重新恢复有效状态。

    使用ostringstream

    例子:

    ostringstream oss;
    string word;
    while(cin>>word)
        oss << word << " ";
    cout<< oss.str() <<endl;

    以上程序完成的事情是:依次读取所有输入的单词,并将单词“写入”到oss流对象,最后使用str函数将oss流对象包含的string以一行打印出来。(PS:最后也有一个空格)

  • 相关阅读:
    First Missing Positive
    Find Minimum in Rotated Sorted Array II
    switch两种写法对比
    常用的前端JavaScript方法封装
    如何保证缓存和数据库的一致性?
    14个前端小知识
    dataTable转换特定的类
    C# MD5 32大写位加密 UTF-8编码
    另一个 SqlParameterCollection 中已包含 SqlParameter
    C#实现数据回滚,A事件和B事件同时执行,其中任何一个事件执行失败,都会返回失败
  • 原文地址:https://www.cnblogs.com/junjie_x/p/7653119.html
Copyright © 2020-2023  润新知