流类简介
C++中凡是数据从一个地方传输到另一个地方的操作都是流的操作。因此,一般意义下的读操作在流数据抽象中被称为(从流中)“提取”,写操作被称为(向流中)“插入”。
iostream流类库的类关系图如下:

图中箭头代表派生关系。ios是抽象基类,提供输入/输出所需的公共操作,它派生出两个类istream和ostream。为了避免多重继承的二义性,从ios派生istream和ostream时,均使用了virtual关键字(虚继承)。
stream类提供了流的大部分输入操作,对系统预定义的所有输入流重载提取运算符>>。ostream类对系统预定义的所有输出流重载插入运算符<<。
C++的iostream类库提供了数百种I/O功能,iostream类库的接口部分包含在几个头文件中。常见的头文件有以下3个:
-
iostream:包含操作所有输入/输出流所需要的基本信息,因此大多数C++程序都应包含这个头文件。该文件含有4个标准流对象,提供了无格式化和格式化的I/O功能。 -
iomanip:包含格式化I/O的带参数流操纵符,可用于指定数据输入/输出的格式。 -
fstream:包含处理文件的有关信息,提供建立文件、读/写文件的各种操作接口。
标准流对象
C++在头文件iostream中为了用户预定义了4个标准流对象,分别是:
-
cin(标准输入流),cin与标准输入设备(键盘)相关联,用于读取数据,可以被重定向为从文件中读取数据。 -
cout(标准输出流),cout与标准输出设备(显示器)相关联,用于输出数据,可以被重定向为向文件里写入数据。 -
cerr(非缓冲错误输出流),cerr与标准错误信息输出设备(显示器)相关联(非缓冲),用于输出出错信息,不能被重定向。 -
clog(缓冲错误输出流),clog与标准错误信息输出设备相关联(缓冲),用于输出出错信息,不能被重定向。
在实际中,cin常用于从键盘输入数据,是流类istream的对象。cout常用于向屏幕输出数据,是流类ostream的对象。
#include <iostream>
using namespace std;
int main() {
int x, y;
cin >> x >> y;
//函数`freopen()`的功能是将`stream`按`mode`指定的模式重定向到路径`path`指向的文件。
//将标准输出定向到文件test.txt
freopen("test.txt", "w", stdout);
if (y == 0) {
cerr << "error" << endl;
} else {
cout << x << " / " << y << " = " << x / y << endl;
}
return 0;
};
控制I/O格式
C++进行I/O格式控制的方式一般有使用流操纵符、设置标志字和调用成员函数。
流操纵符
| 流操纵符 | 作用 |
|---|---|
| endl | 输出一个新行符,并清空流 |
| ends | 输出字符串结束,并清空流 |
| flush | 清空流缓冲区 |
| dec*(默认) | 以十进制形式输入/输出整数 |
| hex | 以十六进制形式输入或输出整数 |
| cot | 以八进制形式输入或输出整数 |
| ws | 提取空白字符 |
| fixed | 以普通小数形式输出浮点数 |
| scientific | 以科学计数法形式输出浮点数 |
| left | 左对齐,即在宽度不足时将填充字符添加到右边 |
| right* | 右对齐,即在宽度不足时将填充字符添加到左边 |
| setbase(int b) | 设置输出整数时的进制,b为8、10、16 |
| setw(int w) | 指定输出宽度为w个字符,或输入字符串时读入w个字符。 一次有效。 |
| setfill(int c) | 在指定输出宽度的情况下, 输出的宽度不足时用 ASCⅡ码为c的字符填充(默认情况是用空格填充) |
| setprecision(int n) | 设置输出浮点数的精度为n。在使用非 fixed且非scientific方式输出的情况下,n即为有效数字最多的位数。如果有效数字位数超过 n,则小数部分四舍五入, 或自动变为科学计数法输出并保留一共 n位有效数字;在使用 fixed方式和scientific方式输出的情况下,n是小数点后面应保留的位数。 |
| setiosflags(fmtflags f) | 通用操纵符。将格式标志f所对应的格式标志位置为1
|
| resetiosflags(fmtflags f) | 通用操纵符。将格式标志f所对应的格式标志位置为0(清除) |
| boolapha | 把ture和false输出为字符串 |
| noboolapha* | 把ture和false输出为1和0
|
| showbase | 输出表示数值进制的前缀 |
| noshowbase* | 不输出表示数值进制的前缀 |
| showpoint | 总是输出小数点 |
| noshowpoint* | 只有当小数部分存在时才显示小数点 |
| showpos | 在非负数值中显示+
|
| noshowpos* | 在非负数值中不显示+
|
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
int n = 65535, m = 20;
//1.分别输出一个整数的十进制、十六进制和八进制表示
cout << "1)" << n << " = " << hex << n << " = " << oct << n << endl;
//1)65535 = ffff = 177777
//2.使用setbase分别输出一个整数的十进制、十六进制和八进制表示
cout << "2)" << setbase(10) << m << " = " << setbase(16) << m << " = " << setbase(8) << m << endl;
//2)20 = 14 = 24
//3.使用showbase和setbase分别输出一个整数的十进制、十六进制和八进制表示
cout << "3)" << showbase;//输出表示数值进制的前缀
cout << setbase(10) << m << " = " << setbase(16) << m << " = " << setbase(8) << m << endl;
//3)20 = 0x14 = 024
return 0;
};
标志字
| 标志常量名 | 值 | 含义 | 输入/输出 |
|---|---|---|---|
| ios::skipws | 0x0001 | 跳过输入中的空白 | I |
| ios::left | 0x0002 | 按输出域左对齐,用填充字符填充右边 | O |
| ios::right* | 0x0004 | 按输入域右对齐,用填充字符填充做左边 | O |
| ios::internal | 0x0008 | 在符号位或基数指示符后填入字符 | O |
| ios::dec* | 0x0010 | 转换为十进制基数形式 | I/O |
| ios::oct | 0x0020 | 转换为八进制基数形式 | I/O |
| ios::hex | 0x0040 | 转换为十六进制基数形式 | I/O |
| ios::showbase | 0x0080 | 在输出中显示基数指示符 | O |
| ios::showpoint | 0x0100 | 在输出浮点数时必须带小数点和尾部的0
|
O |
| ios::uppercase | 0x0200 | 以大写字母表示十六进制数,科学计数法使用大写字母 | O |
| ios::showpos | 0x0400 | 正数前面加+号 |
O |
| ios::scientific | 0x0800 | 科学计数法显示浮点数 | O |
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
double x = 12.34;
cout << "1)" << setiosflags(ios::scientific | ios::showpos) << x << endl;
cout << "2)" << setiosflags(ios::fixed) << x << endl;
cout << "3)" << resetiosflags(ios::fixed) << setiosflags(ios::scientific | ios::showpos) << x << end;
cout << "4)" << resetiosflags(ios::showpos) << x << endl;
//1)+1.234000e+001
//2)+12.34
//3)+1.234000e+001
//4)1.234000e+001
return 0;
};
调用cout的成员函数
| 成员函数 | 作用相同的流操作符 |
|---|---|
| precision(int np) | setprecision(np) |
| width(int nw) | setw(nw) |
| fill(char cFill) | setfill(cFill) |
| setf(long iFlags) | setiosflags(iFlags) |
| unsetf(long iFlags) | resetiosflags(iFlags) |
#include <iostream>
using namespace std;
int main(){
double values[] = {
1.23,
20.3456,
300.4567,
4000.45678,
50000.1234567
};
cout.fill('*');//设置填充字符为`*`
for (int i = 0; i < sizeof(values) / sizeof(double); i++) {
cout << "values[" << i << "] = (";
cout.width(10);//设置输出宽度
cout << values[i] << ")" << endl;
}
/*
values[0] = (******1.23)
values[1] = (***20.3456)
values[2] = (***300.457)
values[3] = (***4000.46)
values[4] = (***50000.1)
*/
cout.fill(' ');//设置填充字符为空格
for (int j = 0; j < sizefo(values) / sizeof(double); j++) {
cout << "values[" << j << "] = ("
cout.width(10);//设置输出宽度
cout.precision(j + 3);//设置保留有效数字
cout << values[j] << ")" << endl;
}
/*
values[0] = ( 1.23)
values[1] = ( 20.35)
values[2] = ( 300.46)
values[3] = ( 4000.46)
values[4] = ( 50000.12)
*/
return 0;
};
调用cin的成员函数
istream类提供了一些公有成员函数,它们可以以不同的方式提取输入流中的数据。
get()函数
#include <iostream>
using namespace std;
int main() {
int n = 0;
char ch;
//当文件没有结束时继续进行循环
while ((ch = cin.get()) != EOF) {
cout.put(ch);
n++;
}
cout << "输入字符共计:" << n << endl;
};
在Windows环境下,当进行键盘输入时,在单独的一行按ctrl + z组合键后再按enter键就代表文件输入结束。
getline()函数
getline()成员函数的原型如下:
istream & getline(char *buf, int bufSize);
其功能是从输入流中的当前字符开始读取bufSize - 1个字符到缓冲区buf,或读到\n为止(哪个条件先满足即按哪个执行)。函数会在buf中读入数据的结尾自动添加串结束标记\0。
istream & getline(char *buf, int bufSize, char delim);
其功能是从输入流中的当前字符开始读取bufSize - 1个字符到缓冲区buf,或读到字符delim为止(哪个条件先满足即按哪个执行)。函数会在buf中读入数据的结尾自动添加\0。
两者的区别在于,前者是读到\n为止,后者是读到指定字符delim为止。字符\n或delim都不会被存入buf中,但会从输入流中取走。
函数getline()的返回值是函数所作用的对象的引用。如果输入流中\n或delim之前的字符个数达到或超过bufSize,则会导致读入操作出错,其结果是:虽然本次读入已经完成,但是之后的读入都会失败。
#include <iostream>
using namespace std;
int main() {
char buf[10];
int i = 0;
//若输入流的一行超过9个字符,则会出错
while (cin.getline(buf, 10)) {
cout << ++i << ":" << buf << endl;
}
cout << "last:" << buf << endl;
return 0;
};
eof()函数
eof()成员函数的原型如下:
bool eof();
eof()函数用于判断输入流是否已经结束。返回值为true表示输入结束。
在应用程序中可以用eof()函数测试是否到达文件尾,当文件操作结束遇到文件尾时,函数返回1;否则返回0。
ignore()函数
ignore()成员函数的原型如下:
istream & ignore(int n = 1, int delim = EOF);
此函数的作用是跳过输入流中的n个字符,或跳过delim及其之前的所有字符(哪个条件先满足就按哪个执行)。两个参数都有默认值。因此cin.ignore()等效于cin.ignore(1, EOF),即跳过一个字符。该函数常用于跳过输入中的无用部分,以便提取有用的部分。
#include <iostream>
using namespace std;
int main() {
char str[30];
while (!cin.eof()) {
cin.ignore(10, ':');
if (!cin.eof()) {
cin >> str;
cout << str << endl;
}
}
return 0;
};
peek()函数
peek()成员函数的原型如下:
int peek();
函数peek()返回输入流中的当前字符,但是并不将该字符从输入流中取走,相当于只是“看了一眼”将要读入的下一个字符,因此叫“窥视”。
cin.peek()不会跳过输入流中的空格和回车符。在输入流已经结束的情况下,cin.peek()返回EOF。