文章目录
To-Do:
- 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种方法可以查询流状态:
-
通过4个相应的函数可以访问这4个标志位:
- bool bad();
- bool eof();
- bool fail();
- bool good();
依次访问3个流状态可以确定当前流的状态
-
通过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
-
的用流本身来测试
此需要一定的技巧, 如:
if (cin) while (cin >> word)
条件状态的管理:
-
通过
std::ios::setstate
可设置特定的流状态:void setstate (iostate state); //其功能等价于: void ios::setstate (iostate state) { clear(rdstate()|state); }
设置的原理与上头的rdstate相同, 都是利用位操作
-
通过
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, endscout<<"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);
-
默认构造函数
构造一个 流与任何文件都没有关联的对象 -
初始化构造函数
构造一个 流对象最初与第一个参数(文件名)标识的文件相关联,并以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模式可以操作任何类型的文件流对象, 且可以与其他任何模式组合使用
-
复制构造函数(delete)
已禁用(无拷贝构造函数), 即IO对象无法被拷贝 -
移动构造函数
获取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的所有数据