单字节操作
单字节 IO 操作 | 说明 |
---|---|
is.get(ch) | 从 istream is 读取下一个字节存入字符 ch 中,返回 is |
os.put(ch) | 将字符 ch 输出到 ostream os,返回 os |
is.get() | 将 is 的下一个字节作为 int 返回 |
is.putback(ch) | 将字符 ch 放回 is,返回 is |
is.unget() | 将 is 向后 移动一个字节,返回 is |
is.peek() | 将下一个字节作为 int 返回,但不从流中删除它 |
使用未格式化 IO 操作读取和写入一个字符
char ch;
while(cin.get(ch))
cout.put(ch);
将字符放回输入流
- peek 返回输入流中下一个字符的副本,但不会将它从流中删除,peek 返回的值仍然留在流中。
- unget 使得输入流向后移动,从而最后读取的值又回到流中。即使不知道最后从流中读取什么值,仍然可以调用 unget。
- putback 是更特殊版本的 unget:它退回从流中读取的最后一个值,但它接受一个参数,此参数必须与最后读取的值相同。
一般情况下,在读取下一个值之前,标准库保证可以最多退回一个值,即标准库不保证在中间不进行读取操作的情况下能连续调用 putback、unget。
char ch1,ch2;
ch1 = cin.peek(); //@ 读而不取
cout << ch1 << endl;
ch2 = cin.get();
cout << ch2 << endl;
char ch1, ch2, ch3, ch4;
cin >> ch1 >> ch2 >> ch3;
cin.unget(); //@ 最后读取的字符回退到流
cin >> ch4; //@ ch3 == ch4
cout << "=================" << endl;
cout << ch1 << endl;
cout << ch2 << endl;
cout << ch3 << endl;
cout << ch4 << endl;
char ch1, ch2, ch3, ch4;
cin >> ch1 >> ch2 >> ch3;
cin.putback(ch3); //@ 最后读取的字符回退到流,参数必须是最后读取的字符
cin >> ch4; //@ ch3 == ch4
cout << "=================" << endl;
cout << ch1 << endl;
cout << ch2 << endl;
cout << ch3 << endl;
cout << ch4 << endl;
从输入操作返回 int 值
peek 和无参版本的 get 都返回 int 类型的值。
返回 int 的原因是,可以返回文件尾后标记,char 范围的每个值都可以表示一个真实的字符,但是取值范围中没有额外的值可以用来表示文件尾。
返回 int 的函数将它们返回的字符首先转换为 unsigned char,然后再将结果提升到 int。
标准库使用负值作为文件尾, cstdio 中定义了 EOF 用于表示文件尾:
while((ch = cin.get()) != EOF)
cout.put(ch);
多字节操作
多字节的未格式化 IO 一次可以操作大块数据,这些操作要求分配并管理用来保存和提取数据的字符数组:
多字节 IO 操作 | 说明 |
---|---|
is.get(sink,size,delim) | 从 is 中最多读取 size 个字节,并保存在字符数组中,sink 表示字符数组的起始地址,读取过程中直至遇到字符 delim 或读取 size 个字节或遇到文件尾时停止。如果遇到 delim,则将其保留在输入流中,不读取出来存入 sink。 |
is.getline(sink,size,delim) | 与接受三个参数的 get 版本类似,但会读取并丢弃 delim。 |
is.read(sink,size) | 读取最多 size 个字节,存入字符数组 sink 中,返回 is。 |
is.gcount() | 返回上一个未格式化读取操作从 is 读取的字节数。 |
os.write(source,size) | 将字符数组 source 中的 size 个字节写入 os,返回 os。 |
is.ignore(size,delim) | 读取并忽略最多 size 个字符,包括 delim,与其他未格式化函数不同,ignore 有默认参数,size 的默认值是1,delim 的默认值为文件尾。 |
get 和 getline 接受相同的参数,sink 表示一个 char 数组,用来表示数据。两个函数都一直读取数据,直到下面的条件之一发生:
- 已读取到 size-1 个字符
- 遇到文件尾
- 遇到分隔符
两个函数的差别是对分隔符的处理,get 将分隔符留在 istream 中的下一个字符,而 getline 则读取并丢弃分隔符,无论哪个函数都不会将分隔符保存到 sink 中。
确定读取了多少个字符
调用 gcount 可以确定最后一个未格式化输入操作读取了多少个字符,应该在任何后续未格式化输入操作之前调用 gcount 。特别是,将字符退回流的单字符操作也属于未格式化输入操作。如果在调用 gcount 之前调用了 peek,unget,putback,则 gcount 的返回值为 0。
低层函数容易出错
如果把 get 或者 peek 的返回值赋予一个char 而不是 int,则因为不同的编译平台对 char 有不同的解释,如果将 char 解释为 unsigned char :
char ch;
while((ch = cin.het()) != EOF)
cout.put(ch); //@ 因为如果读到 EOF 将其赋值给 char,将导致死循环