C++ Stream IO

c++ IO由stream 完成,所谓的输入输出,就是字符流入stream和字符流出stream的过程,其中最重要的莫过于

istream定义input stream,用来读取数据

ostream定义output stream,用来写数据

IOStram定义了数个istream和ostream全局对象,对应标准IO的3个通道

在linux中的文件描述符为

  • 0 : stdin : cin

  • 1 : stdout : cout

  • 2 : stderr : cerr, clog

Manipulator

操作符 class 意义
endl ostream 输出\n并刷新
ends ostream 输出\0并刷新
flush ostream 刷新
ws istream 跳过空白字符

other manipulator

<<

basic_ostream将<<定义为output操作符,对所有内建类型进行了重载,除了null和nullptr_t,但是包括char 和 void

得益于其拓展性,因此我们可以对自定义类型进行重载,这样就可以保证对任意类型都会推断出正确的打印函数

1
2
3
4
5
6
7
struct test {
std::string str;
};

std::ostream & operator<<(std::ostream &out, test t) {
return out << t.str;
}

要注意的是,重载的<<运算符必须是全局的,因此对于要输出private成员的class我们需要设置friend属性

>> & <<

>>被定义成input运算符

<<被定义成output运算符

可以从方向判断数据的流向

例如

1
2
std::cout << "hello"; //流入cout缓冲区
std::cin >> i; //从cin流入i

Stream State(flag)

常量 意义
goodbit 一切都好,没有任何其他bit被设置
eofbit 遇到end-of-file
failbit 错误,某个IO未完成,例如输入int但却混杂了一个char(格式错误)
badbit 毁灭性错误,例如文件指针设置错误导致的读写失败

字母在输入的时候并不会隐式转换为整形,以下是测试代码

1
2
3
4
5
6
7
8
9
10
#include <iostream>
using namespace std;
int main() {
int k;
cin >> k;
if (cin.badbit) {
cout << "the bad bit has been set" << endl;
}
return 0;
}

Handle Stream State

函数 意义
good() 返回goodbit
eof() 返回eofbit
fail() 返回failbit或者badbit
bad() 返回badbit
rdstate() 返回当前设置的所有flag
clear() 清除所有flag
clear(state) 清除所有flag并设置state
setstate(state) 设置state flag

Stream Boolean

成员函数 意义
operator bool Stream是否已经出错,!fail()
operator ! stream是否已经出错,fail()

Input function

int istream::get()

读取一个字符

返回读取的字符或者EOF

istream& istream::get (char& c)

把下一个字符赋值给c

通过返回stream可以判断是否读取成功

istream& get(char *, streamsize)

终止条件是下一个字符是换行符,但不会将其读取,还会保留在缓冲区中

1
2
3
4
5
basic_istream &
get(char_type* __s, streamsize __n)
{
return get(__s, __n, this->wident('\n'));
}

以下代码,除了第一个std::cin.get()起作用,其他的都是直接读取缓冲区的\n

1
2
3
4
5
6
7
8
9
10
#include <iostream>

int main() {
char a[10];
std::cin.get(a, 10);
std::cin.get(a, 10);
std::cin.get(a, 10);
std::cout << a << std::endl;
return 0;
}

原因在于遇到\n就结束,但是并不从缓冲区中把\n取走

因此接下来的每次读取都会遇到残留在输入缓冲区里面的\n

所以要想办法

  • \n取走,例如,加入std::get()取走\n
  • 直接清空缓冲区,std::cin.ignore()

istream& istream::get(char* str, streamsize count, char delim)

  • 读取的字符序列以null结尾
  • 不会读取终止符delim

istream& istream::getline(char* str, streamsize count)

istream& istream::getline(char* str, streamsize count, char delim)

  • 会读取结束字符 delim(\n)
  • 但是str不会存储结束字符

其余与get一样