C++ Primer第八章笔记

To-Do:

  1. P287 string流
    完全还没有开始

8.0: IO库函数补充:

8.1: IO类:

8.1.0: IO类继承关系:

在这里插入图片描述

遵从的类继承机制可非常方便的使用IO库的成员

宽字符版本的IO:

其中每个IO类都有其对应的宽字符版本用于操作wchar_t类型的数据, 并且其定义在相同的头文件中:

如: istream 对应的 wistream , 前头的w就表示宽字符

8.1.1: IO对象无法拷贝与赋值:

如同之前的operator << 中所说, IO对象无法被拷贝与赋值, 所以无法作为形参或返回类型

所以, 通常在以上场合使用IO对象的引用, 并且不能是const类型的引用, 因为读写IO对象时会改变其状态

8.1.2: 条件状态:

IO操作很可能发生错误, 通过条件状态可以访问和操作

条件状态的保存位置:

每个IO对象都有各自的流状态

保存在iostate类型的对象中, 而iostate定义在ios_base中, 其为枚举类型, ios中定义了4中iostate类型的constexpr值:

  • eofbit: 已到达文件尾
  • failbit: 非致命的输入/输出错误,可挽回
  • badbit: 致命错误, 为系统级别的错误, 一旦被置1, 流就无法在使用了
  • goodbit: No error. 当上头的3个都没有时置1

其中0表示正常, 1表示被设置

条件状态的查询:

有3种方法可以查询流状态:

  1. 通过4个相应的函数可以访问这4个标志位:

    • bool bad();
    • bool eof();
    • bool fail();
    • bool good();

    依次访问3个流状态可以确定当前流的状态

  2. 通过rdstate()函数:

std::ios::rdstate定义在ios中, 其声明为:

iostate rdstate() const;

可以看到返回的是iostate对象, 具体返回值为:

在这里插入图片描述

即其根据4个标志位决定返回的枚举值

注意这个表是这么看的:

  • 上头的4个标志位按照二进制组成了rdstate的返回值iostate

    其中goodbit为最低位, 而后依次向上, badbit为最高位

所以有:

	cout << cout.bad() << endl;
    cout << cout.eof() << endl;
    cout << cout.fail() << endl;
    cout << cout.good() << endl;
    cerr << cout.rdstate() << endl;
    cerr << "__________________" <<endl;  
    cout.setstate(ios_base::failbit);
    
    cerr << cout.bad() << endl;
    cerr << cout.eof() << endl;
    cerr << cout.fail() << endl;
    cerr << cout.good() << endl;
    cerr << cout.rdstate() << endl;
    cerr << "__________________" <<endl;  
    
    cout.clear();
    cout.setstate(ios_base::badbit);
    
    cerr << cout.bad() << endl;
    cerr << cout.eof() << endl;
    cerr << cout.fail() << endl;
    cerr << cout.good() << endl;
    cerr << cout.rdstate() << endl;
    cerr << "__________________" <<endl; 

    cout.clear();
    cout.setstate(ios_base::eofbit);
    
    cerr << cout.bad() << endl;
    cerr << cout.eof() << endl;
    cerr << cout.fail() << endl;
    cerr << cout.good() << endl;
    cerr << cout.rdstate() << endl;
    cerr << "__________________" <<endl;

输出结果:

0
0
0
1
0


0
0
1
0
4


1
0
1
0
1


0
1
0
0
2


  1. 的用流本身来测试

    此需要一定的技巧, 如:

    if (cin)
    
    while (cin >> word)
    

条件状态的管理:

  1. 通过std::ios::setstate可设置特定的流状态:

    void setstate (iostate state);
    
    //其功能等价于:
    void ios::setstate (iostate state) {
      clear(rdstate()|state);
    }
    

    设置的原理与上头的rdstate相同, 都是利用位操作

  2. 通过std::ios::clear清空流状态(恢复正常)

    void clear (iostate state = goodbit);
    

表示条件状态的四个常量:

这4个常量都是定义在ios_base中, 表示流状态

注意, 这里是4个表示流状态的常量, 和上头的储存流状态的4个变量不一样, 后者是根据流的当前状态设置的, 但是前者不变!

常量 含义 failbit标记位的值 eofbit标记位的值 badbit标记位的值 转化为10进制
ios::failbit 输入(输出)流出现非致命错误,可挽回 1 0 0 4
ios::badbit 输入(输出)流出现致命错误,不可挽回 0 0 1 2
ios::eofbit 已经到达文件尾 0 1 0 1
ios::goodbit 流状态完全正常 0 0 0 0

这4个常量主要用来设置流的标志位, 根据表中的特点, 可以很快的用位操作设置上头的4个流状态变量

如:

cerr << cout.bad() << endl;
cerr << cout.eof() << endl;
cerr << cout.fail() << endl;
cerr << cout.good() << endl;
cout.setstate(ios_base::failbit);
cerr << cout.bad() << endl;
cerr << cout.eof() << endl;
cerr << cout.fail() << endl;
cerr << cout.good() << endl;

输出结果:

0
0
0
1
0
0
1
0

8.1.3: 管理输出缓冲:

缓冲区的概念在C Primer Plus 中介绍的很明确了, 这里仅仅对C++中的缓冲机制做拓展

缓冲区刷新的原因:

  • 程序正常结束
    为main中return需要执行的具体操作的一部分

  • 缓冲区满了

  • 使用特定的manipulator
    常用的有: endl, flush, ends

     cout<<"hi"<<endl ;    
    // 插入换行,同时刷新输出缓冲区
    //其意为end line 所以换行
    
    cout<<"hi"<<ends;      
    //末尾插入null, 刷新缓存区
    //其意为end string (const string *), 所以加null
    
    cout<<"hi"<<flush;      
    // 刷新缓存区,不添加任何数据
    
    
  • 当输出流关联到另一个流时, 如cin & cerr都关联到cout, 读写cin 或 cerr时会导致cout的缓冲区刷新

    可使用tie将两个流关联起来:

    //get (1)	
    ostream* tie() const;
    
    //set (2)	
    ostream* tie (ostream* tiestr);
    
    • 返回值:
      pointer to the stream object tied before the call, or a null pointer in case the stream was not tied.
  • 使用unitbuf设置流的内部状态, 使所有输出都刷新缓冲区, 如:

    cout<<unitbuf<<"first"<<"second"<<nounitbuf;
    
    //等价于
    cout<<"first"<<flush<<"second"<<flush;
    

8.2: 文件输入输出:

头文件fstream中定义了三个类型:

  • ifstream: 支持读取数据
  • ofstream: 支持写入数据
  • fstream: 支持IO

可以和普通的IO成员一样使用相同的操作方式, 同时fstream中定义了一些专有操作:

构造&析构函数:

//default (1)	
fstream();

//initialization (2)	
explicit fstream (const char* filename,
                  ios_base::openmode mode = ios_base::in | ios_base::out);
explicit fstream (const string& filename,
                  ios_base::openmode mode = ios_base::in | ios_base::out);

//copy (3)	
fstream (const fstream&) = delete;

//move (4)	
fstream (fstream&& x);
  1. 默认构造函数
    构造一个 流与任何文件都没有关联的对象

  2. 初始化构造函数
    构造一个 流对象最初与第一个参数(文件名)标识的文件相关联,并以mode指定的模式打开

    关于filename:

    filename可以是string类型, 或是C string

    关于mode:

    member constant stands for access
    in input 以读模式打开文件
    out output 以写模式打开文件
    binary binary 以二进制模式打开文件
    ate at end 打开文件并将输出位置设置为文件末尾( 相当于在末尾追加内容)
    app append 文件输出操作都附加到原有内容后
    trunc truncate 打开文件并清空原有内容
    • 只有设定了out, 才能设定trunc模式
    • 只要trunc没被设定, 就可以设定app模式
    • app模式默认以输出方式打开文件
    • 防止out清空原有内容, 需要同时设置app模式, 或是in模式
    • ate & binary模式可以操作任何类型的文件流对象, 且可以与其他任何模式组合使用
  3. 复制构造函数(delete)
    已禁用(无拷贝构造函数), 即IO对象无法被拷贝

  4. 移动构造函数
    获取x的内容

public成员函数:

void open (const char* filename,
           ios_base::openmode mode = ios_base::in | ios_base::out);
void open (const string& filename,
           ios_base::openmode mode = ios_base::in | ios_base::out);
  • 打开指定的文件, 功能与构造函数相似
  • 如果已经有文件被打开, 则函数调用失败
  • 如果文件打开失败, 则会将流的failbit置1
bool is_open() const;

用于检测文件是否已经被打开

void close();

用于断开与流关联的文件, 即关闭打开的文件

  • 如果没有与任何文件相关联, 则函数调用失败
  • 使用close()后会刷新流缓冲区
  • 任何fstream对象销毁时, 都会调用close()关闭已打开的文件
filebuf* rdbuf() const;

返回一个指向fstream对象内部filebuf文件缓冲区的指针

  • 注意这与当前关联的流缓冲区, 即ios::rdbuf的返回值不一定相同
//copy (1)	
fstream& operator= (const fstream&) = delete;
//move (2)	
fstream& operator= (fstream&& rhs);

功能类似移动构造函数

返回*this

void swap (fstream& x);

用于交换x与*this的所有数据

8.3: string流:

发布了17 篇原创文章 · 获赞 7 · 访问量 1343

猜你喜欢

转载自blog.csdn.net/qq_42683011/article/details/104058924
今日推荐