总结
流是进出程序的字节流。缓冲区是内存中的临时存储区域,是程序与文件或其他 I/O 设备之间的桥梁。信息在缓冲区和文件之间传输时,将使用设备(如磁盘驱动器)处理效率最高的尺寸以大块数据的方式进行传输。信息在缓冲区之间传输时,是逐字节传输的,这种方式对于程序中的处理操作更为方便。C++ 通过将一个被缓冲流同程序及其输入源相连来处理输入。同样,C++ 也通过将一个被缓冲流与程序及其输出目标相连来处理输出。iostrea 和 fstream 文件构成了 I/O 类库,该类库定义了大量用于管理流的类。包含了 iostream 文件的 C++ 程序将自动打开 8 个流,并使用 8 个对象管理它们。cin 对象管理标准输入流,后者默认与标准输入设备(通常为键盘)相连;cout 对象管理标准输出流,后者默认与标准输出设备(通常为显示器)相连;cerr 和 clog 对象管理与标准错误设备(通常为显示器)相连的未被缓冲的流和被缓冲的流。这 4 个对象都有用于宽字符的副本,它们是 wcin、wcout、wcerr 和 wclog。
I/O 类库提供了大量有用的方法。istream 类定义了多个版本的抽取运算符(>>),用于识别所有基本的 C++ 类型,并将字符输入转换为这些类型。get() 方法族和getline() 方法为单字符输入和字符串输入提供了进一步的支持。同样,ostream 类定义了多个版本的插入运算符(<<),用于识别所有的 C++ 基本类型,并将它们转换为相应的字符输出。put() 方法对单字符输出提供了进一步的支持。wistream 和 wostream 类对宽字符提供了类似的支持。
使用 ios_base 类方法以及文件 iostream 和 iomanip 中定义的控制符(可与插入运算符拼接的函数),可以控制程序如何格式化输出。这些方法和控制符使得能够控制计数系统、字段宽度、小数位数、显示浮点变量时采用的计数系统以及其他元素。
fstream 文件提供了将 iostream 方法扩展到文件 I/O 的类定义。ifstream 类是从 istream 类派生而来的。通过将 ifstream 对象与文件关联起来,可以使用所有的 istream 方法来读取文件。同样,通过将 ofstream 对象与文件关联起来,可以使用 ostream 方法来写文件;通过将 fstream 对象与文件关联起来,可以将输入和输出方法用于文件。
要将文件与流关联起来,可以在初始化文件流对象时提供文件名,也可以先创建一个文件流对象,然后用 open() 方法将这个流与文件关联起来。close() 方法终止流与文件之间的连接。类构造函数和open()方法接受可选的第二个参数,该参数提供文件模式。文件模式决定文件是否被读和/或写、打开文件以便写入时是否截短文件、试图打开不存在的文件时是否会导致错误、是使用二进制模式还是文本模式等。
文本文件以字符格式存储所有的信息,例如,数字值将被转换为字符表示。常规的插入和抽取运算符以及 get() 和 getline() 都支持这种模式。二进制文件使用计算机内部使用的二进制表示来存储信息。与文本文件相比,二进制文件存储数据(尤其是浮点值)更为精确、简洁,但可移植性较差。read() 和 write() 方法都支持二进制输入和输出。
seekg() 和 seekp() 函数提供了对文件的随机存取。这些类方法使得能够将文件指针放置到相对于文件开头、文件尾和当前位置的某个位置。tellg() 和 tellp() 方法报告当前的文件位置。
sstream 头文件定义了 istringstream 和 ostringstream 类,这些类使得能够使用 istream 和 ostream 方法来抽取字符串中的信息,并对要放入到字符串中的信息进行格式化。
复习题
-
istream 文件在 C++ I/O 中扮演何种角色?
答:iostream 文件定义了用于管理输入和输出的类、常量和操纵符,这些对象管理用于处理 I/O 的流和缓冲区。该文件还创建了一些标准对象(cin、cout、cerr 和 clog 以及对应的宽字符对象),用于处理与每个程序相连的标准输入和输出流。 -
为什么键入数字(如121)作为输入要求程序进行转换?
答:键盘输入生成一系列字符。输入121将生成3个字符,每个字符都由一个1字节的二进制码表示。要将这个值存储为 int 类型,则必须将这 3 个字符转换为 121 值的二进制表示。 -
标准输出与标准错误之间有什么区别?
答:在默认情况下,标准输出和标准错误都将输出发送给标准输出设备(通常为显示器)。然而,如果要求操作系统将输出重定向到文件,则标准输出将与文件(而不是显示器)相连,但标准错误仍与显示器相连。 -
为什么在不为每个类型提供明确指示的情况下,cout 仍能够显示不同的 C++ 类型?
ostream 类为每种 C++ 基本类型定义了一个 operator<<() 重载。 -
输出方法的定义哪一特征让您能够拼接输出?
答:返回 ostream & 类型使得能够拼接输出。 -
编写一个程序,要求用户输入一个整数,然后以十进制、八进制和十六进制显示该整数。在宽度为 15 个字符的字段中显示每种形式,并将它们显示在同一行上,同时使用 C++ 基数前缀。
#include<iostream> #include<iomanip> int main() { int num; std::cout << "Input an integer: "; std::cin >> num; std::cout.setf(std::ios_base::showbase); std::cout << std::hex << std::setw(15) << num << std::dec << std::setw(15) << num << std::oct << std::setw(15) << num << std::endl; return 0; }
-
编写一个程序,请求用户输入下面的信息,并按下面的格式显示它们:
Enter your name: Billy Gruff Enter your hourly wages: 12 Enter number of hours worked: 7.5 Fisrt format: Billy Gruff: $ 12.00: 7.5 Second format: Billy Gruff : $12.00 :7.5
答:
#include<iostream> #include<iomanip> const int LIM = 20; int main() { using namespace std; char name[20]; float hourly; float hours; cout << "Enter your name: "; cin.get(name, LIM).get(); cout << "Enter your hourly wages: "; cin >> hourly; cout << "Enter number of hours worked: "; cin >> hours; cout.setf(ios::showpoint); cout.setf(ios::fixed, ios_base::floatfield); cout << "Fisrt format:\n"; cout.setf(ios_base::right, ios_base::adjustfield); cout << setw(20) << name << ": $" << setprecision(2) << setw(10) << hourly << ":" << setprecision(1) << setw(5) << hours << "\n"; cout << "Second format:\n"; cout.setf(ios_base::left, ios_base::adjustfield); cout << setw(20) << name << ": $" << setprecision(2) << setw(10) << hourly << ":" << setprecision(1) << setw(5) << hours << "\n"; return 0; }
-
对于下面的程序:
rq17-8.cpp #include <iostream> #include <iomanip> int main() { using namespace std; char ch; int ct1 = 0; cin >> ch; while ( ch != 'q' ) { ct1++; cin >> ch; } int ct2 = 0; cin.get(ch); while ( ch != 'q' ) { ct2++; cin.get(ch); } cout << "ct1 = " << ct1 << "; ct2 = " << ct2 << "\n"; return 0; }
如果输入如下,该程序将打印什么内容?
I see a q<Enter> I see a q<Enter>
答:
ct1 = 5; ct2 = 9;
该程序的前半部分忽略空格和换行符,而后半部分没有。注意,程序的后半部分从第一个 q 后面的换行符开始读取,将换行符计算在内。 -
下面的两条语句都读取并丢弃行尾之前的所有字符(包括行尾)。这两条语句的行为在哪方面不同?
while (cin.get() != '\n') { continue; } cin.ignore(80, '\n');
答:第一条语句可以除去包括换行符在内的该行的所有字符,而第二条语句虽然也能这样做,但最多只能去除80个字符,如果在清除了80个字符时仍然没有遇到换行符,就将剩下的字符留在缓冲区。