第十一章流类库与输入 / 输出
本章主要内容 I/O 流的概念 输出流 输入流 输入 / 输出流 2
I/O 流的概念 当程序与外界环境进行信息交换时, 存在着两个对象, 一个是程序中的对象, 另一个是文件对象 流是一种抽象, 它负责在数据的生产者和数据的消费者之间建立联系, 并管理数据的流动 程序建立一个流对象, 并指定这个流对象与某个文件对象建立连接, 程序操作流对象, 流对象通过文件系统对所连接的文件对象产生作用 读操作在流数据抽象中被称为 ( 从流中 ) 提取, 写操作被称为 ( 向流中 ) 插入 3
输出流 ostringstream 类向字符串写入数据 输出流 最重要的三个输出流是 ostream ofstream 类支持磁盘文件输出 4
输出流输出流对象 预先定义的 ostream 类对象 : cout 标准输出 cerr 标准错误输出, 没有缓冲, 发送给它的内容立即被输出 clog 类似于 cerr, 但是有缓冲, 缓冲区满时被输出 5
输出流输出流对象 ofstream 类支持磁盘文件输出 如果在构造函数中指定一个文件名, 当构造这个文件时该文件是自动打开的 ofstream myfile("filename"); 可以在调用默认构造函数之后使用 open 成员函数打开文件 ofstream myfile; // 声明一个静态文件输出流对象 myfile.open("filename"); // 打开文件, 使流对象与文件建立联系 在构造对象或用 open 打开文件时可以指定模式 ofstream myfile("filename", ios_base::out ios_base::binary); 6
输出流插入运算符 (<<) 插入 (<<) 运算符是所有标准 C++ 数据类型预先设计的 用于传送字节到一个输出流对象 7
输出流} 控制输出格式 控制输出宽度 为了调整输出, 可以通过在流中放入 setw 操纵符或调用 width 成员函数为每个项指定输出宽度 setw 和 width 都不截断数值 setw 和 width 仅影响紧随其后的域, 在域输出结束后宽度恢复默认值 ( 必要的宽度 ) 例 11-1 使用 width 控制输出宽度 #include <iostream> using namesoace std; int main() { double values[] = { 1.23, 35.36, 653.7, 4358.24 }; for(int i = 0; i < 4; i++) { cout.width(10); cout << values[i] << endl; } return 0; 输出结果 : 1.23 35.36 653.7 4358.24 8
输出流} 例 : 使用 * 填充 缺省为空格 使用 setfill 操纵符或 fill 成员函数设置填充字符 持久影响 #include <iostream> using namespace std; int main() { double values[]={ 1.23, 35.36, 653.7, 4358.24 }; cout.fill('*'); for(int i = 0; i < 4; i++) { cout.width(10); cout << values[i] << '\n'; } return 0; 输出结果 : ******1.23 *****35.36 *****653.7 ***4358.24 9
输出流} 例 11-2 使用 setw 指定宽度 #include <iostream> #include <iomanip> #include <string> using namespace std; int main() { double values[] = { 1.23, 35.36, 653.7, 4358.24 }; string names[] = { "Zoot", "Jimmy", "Al", "Stan" }; for (int i = 0; i < 4; i++) cout << setw(6) << names[i] << setw(10) << values[i] << endl; return 0; 输出结果 : Zoot 1.23 Jimmy 35.36 Al 653.7 Stan 4358.24 10
出流对齐方式 输 输出流默认为右对齐文本 setiosflags 操作符来设置格式标志, 持久影响 smanip setiosflags ( ios_base::fmtflags mask ); resetiosflags 操作符来清除格式标志 smanip resetiosflags ( ios_base::fmtflags mask ); 掩码 mask 可用位或 进行组合 : 对齐 :ios_base::left, ios_base::right 进制 :ios_base::dec, ios_base::oct, ios_base::hex 浮点 :ios_base::fixed, ios_base::scientific 其他 :ios_base::skipws 等 11
例 11-3 设置对齐方式 输出流} #include <iostream> #include <iomanip> #include <string> using namespace std; int main() { 输出结果 : Zoot 1.23 Jimmy 35.36 Al 653.7 Stan 4358.24 double values[] = { 1.23, 35.36, 653.7, 4358.24 }; string names[] = { "Zoot", "Jimmy", "Al", "Stan" }; for (int i=0;i<4;i++) cout << setiosflags(ios_base::left) << setw(6) << names[i] << resetiosflags(ios_base::left) << setw(10) << values[i] << endl; return 0; 12
输出流精度 浮点数输出精度默认值是 6 setprecision 操纵符或 precision 成员函数来设置精度 3466.9768 显示为 3466.98 若设置了 ios_base::fixed, 定点格式 ( 没有指数部分 ):3466.976800 若设置了 ios_base::scientific, 科学格式 : 3.466977e+003 若都未设置, 精度值确定总的有效位数, 否则确定小数点后小数位数 13
输出流} 例 11-4 控制输出精度 输出结果 : #include <iostream> #include <iomanip> Zoot 1 #include <string> Jimmy 4e+001 using namespace std; Al 7e+002 int main() { Stan 4e+003 double values[] = { 1.23, 35.36, 653.7, 4358.24 }; string names[] = { "Zoot", "Jimmy", "Al", "Stan" }; for (int i=0;i<4;i++) cout << setiosflags(ios_base::left) << setw(6) << names[i] << resetiosflags(ios_base::left) << setw(10) << setprecision(1) << values[i] << endl; return 0; 14
输出流进制 默认进制是 dec( 十进制 ) dec oct 和 hex 操纵符设置输入和输出的默认进制 15
输出流文件输出流成员函数 输出流成员函数有三种类型 : 与操纵符等价的成员函数 执行非格式化写操作的成员函数 其它修改流状态且不同于操纵符或插入运算符的成员函数 16
输出流文件输出流成员函数 open 函数把流与一个特定的磁盘文件关联起来 需要指定打开模式 默认模式 :ios_base::out put 函数把一个字符写到输出流中 write 函数把内存中的一块内容写到一个文件输出流中 seekp 和 tellp 函数操作文件输出流的内部指针 close 函数关闭与一个文件输出流关联的磁盘文件 错误处理函数在写到一个流时进行错误处理 17
出流例 11-5 向文件输出 #include <fstream> using namespace std; struct Date { int mondy, day, year; }; int main() { Date dt = { 6, 10, 92 }; ofstream file("date.dat", ios_base::binary); file.write(reinterpret_cast<char *>(&dt), sizeof(dt)); file.close(); return 0; } 输18
输出流二进制输出文件 以通常方式构造一个流, 然后使用 setmode 成员函数, 在文件打开后改变模式 使用 ofstream 构造函数中的模式参量指定二进制输出模式 ios_base::binary, 默认是文本模式 19
输出流20 字符串输出流 ostringstream 用于构造字符串 功能 支持 ofstream 类的除 open close 外的所有操作 str 函数可以返回当前已构造的字符串 典型应用 将数值转换为字符串
输出流} 例 11-6 字符串输出流应用 #include <iostream> #include <sstream> #include <string> 输出结果 : using namespace std; 5 template <class T> 1.2 inline string tostring(const T &v) { ostringstream os; // 创建字符串输出流 os << v; // 将变量 v 的值写入字符串流 return os.str(); // 返回输出流生成的字符串 } int main() { string str1 = tostring(5); cout << str1 << endl; string str2 = tostring(1.2); cout << str2 << endl; return 0; 21
输入流 istringstream 类支持从字符串中读取数据 输入流 重要的输入流类 : istream 类最适合用于顺序文本模式输入 cin 是其实例 ifstream 类支持磁盘文件输入 22
输入流输入流对象 如果在构造函数中指定一个文件名, 在构造该对象时该文件便自动打开 ifstream myfile("filename"); 在调用默认构造函数之后使用 open 函数来打开文件 ifstream myfile;// 建立一个文件流对象 myfile.open("filename",); // 打开文件 "filename 打开文件时可以指定模式 ifstream myfile("filename", ios_base::in ios_base::binary); 23
输入流提取运算符 (>>) 提取运算符 (>>) 对于所有标准 C++ 数据类型都是预先设计好的 是从一个输入流对象获取字节最容易的方法 ios 类中的很多操纵符都可以应用于输入流 但是只有少数几个对输入流对象具有实际影响, 其中最重要的是进制操纵符 dec oct 和 hex 24
输入流输入流成员函数 open 函数把该流与一个特定磁盘文件相关联 get 函数的功能与提取运算符 (>>) 很相像, 主要的不同点是 get 函数在读入数据时包括空白字符 getline 的功能是从输入流中读取多个字符, 并且允许指定输入终止字符, 读取完成后, 从读取的内容中删除终止字符 read 成员函数从一个文件读字节到一个指定的内存区域, 由长度参数确定要读的字节数 如果给出长度参数, 当遇到文件结束或者在文本模式文件中遇到文件结束标记字符时结束读取 25
输入流输入流成员函数 seekg 函数用来设置文件输入流中读取数据位置的指针 tellg 函数返回当前文件读指针的位置 close 函数关闭与一个文件输入流关联的磁盘文件 26
输入流例 11-9 从文件读二进制记录 #include <iostream> #include <fstream> #include <cstring> using namespace std; struct SalaryInfo { unsigned id; double salary; }; int main() { SalaryInfo employee1 = { 600001, 8000 }; ofstream os("payroll", ios_base::out ios_base::binary); os.write(reinterpret_cast<char *>(&employee1), sizeof(employee1)); os.close(); 27
输入流} ifstream is("payroll", ios_base::in ios_base::binary); if (is) { SalaryInfo employee2; is.read(reinterpret_cast<char *>(&employee2), sizeof(employee2)); cout << employee2.id << " " << employee2.salary << endl; } else { cout << "ERROR: Cannot open file 'payroll'." << endl; } is.close(); return 0; 28
输入流31 字符串输入流 istringstream 用于从字符串读取数据 在构造函数中设置要读取的字符串 功能 支持 ifstream 类的除 open close 外的所有操作 典型应用 将字符串转换为数值
输入流1.2 例 11-12 字符串输入流应用 #include <iostream> #include <sstream> 输出结果 : #include <string> 5 using namespace std; template <class T> inline T fromstring(const string &str) { istringstream is(str); // 创建字符串输入流 T v; is >> v; // 从字符串输入流中读取变量 v return v; // 返回变量 v } int main() { int v1 = fromstring<int>("5"); cout << v1 << endl; double v2 = fromstring<double>("1.2"); cout << v2 << endl; return 0; } 32
输入输出流输入输出流 iostream 类对象可以是数据的源或目的 fstream 类支持磁盘文件输入和输出 stringstream 类支持面向字符串的输入和输出 33
小结与复习建议 主要内容 I/O 流的概念 输出流 输入流 输入 / 输出流 达到的目标 理解 I/O 流的概念, 学会使用 I/O 流类库实现文件输入 / 输出及格式控制 46