I/O 流概念与流库结构

一个程序创建一个 流对象: * 当程序与外部环境交换信息时,有两个对象:一个是 程序中的对象,另一个是 文件对象。 * 流是一种抽象,负责在 数据生产者数据消费者 之间建立连接并管理数据流。

指定该流对象与某个文件对象建立连接。程序操作流对象,该对象通过文件系统对连接的文件对象进行操作。

操作系统将键盘、屏幕、打印机和通信端口视为扩展文件,这种处理是通过操作系统的设备驱动程序实现的。这些设备相当于磁盘文件。

一般意义上的读操作在流数据对象中称为 提取(来自流),写操作称为 插入(到流中)。

I/O 流类列表

输出流

三个最重要的输出流: * ostream * ofstream * ostringstream

预定义的输出流对象: * cout 标准输出 * cerr 标准错误输出,无缓冲,发送到它的内容立即输出。 * clog 类似于 cerr,但有缓冲,缓冲区满时输出。

构造输出流对象

构造文件输出流的常用方法: 1. 使用默认构造函数,然后调用 open 成员函数。

1
2
ofstream myFile; //定义一个静态文件输出流对象
myFile.open("filename"); //打开文件,建立流对象与文件之间的连接
2. 在调用构造函数时指定文件名:
1
ofstream myFile("filename");
3. 在构造对象或使用 open 打开文件时可以指定模式:
1
ofstream myFile("filename", ios_base::out | ios_base::binary);
4. 还可以使用同一个流对象依次打开不同的文件(一次只能打开一个)。

文件输出流成员函数

三种类型: * 与操纵符等效的成员函数。 * 执行无格式写操作的成员函数。 * 其他修改流状态的成员函数,与操纵符或插入运算符不同。

文件输出流成员函数 * open 函数 * 将流与特定磁盘文件关联。 * 需要指定打开模式。 * put 函数 * 向输出流写入一个字符。 * write 函数 * 将内存中的一块内容写入文件输出流。 * seekp 和 tellp 函数 * 操作文件流的内部指针。 * close 函数 * 关闭与文件输出流关联的磁盘文件。 * 错误处理函数 * 写入流时的错误处理。

输出到文本文件

系统将标准输出设备显示视为文本文件,因此我们使用输出到标准设备作为例子来介绍文本文件输出格式控制。

插入运算符

插入(<<)运算符:为所有标准 C++ 数据类型预设计,用于将字节传输到输出流对象。

操纵符

插入运算符与操纵符一起工作以控制输出格式。 * 许多操纵符在 ios_base 类中定义(如 hex())和 <iomanip> 头文件中定义(如 setprecision())。 * 控制输出宽度:在流中放置 setw 操纵符或调用 width 成员函数以指定每个项目的输出宽度。 > setw 和 width 仅影响紧随其后的输出项,但其他流格式操纵符在更改之前保持有效。 * dec、oct 和 hex 操纵符设置输入和输出的默认基数。

设置宽度

width 源代码 setw 源代码

width 成员函数在 iostream 中声明。如果使用带参数的 setw 或任何其他操纵符,必须包含 iomanip

对齐

设置对齐源代码

setiosflags 操纵符

在本程序中,通过使用带参数的 setiosflags 操纵符设置左对齐。setiosflags 在 iomanip 头文件中定义。 * 参数 ios_base::left 是 ios_base 的静态常量,因此引用时必须包含 ios_base:: 前缀。 * 在这里,我们需要使用 resetiosflags 操纵符来 关闭左对齐标志。setiosflags 与 width 和 setw 不同,它的 效果是持久的,直到使用 resetiosflags 恢复默认值。 * setiosflags 的参数是流的格式标志值,可以使用按位或(|)运算符 组合

精度

浮点输出精度的默认值为 6,例如:3466.98。 * 要更改精度:setprecision 操纵符(在 iomanip 头文件中定义)。 * 如果未指定 fixed 或 scientific,则精度值表示有效数字的数量。 * 如果设置了 ios_base::fixed 或 ios_base::scientific,则精度值表示小数点后的位数。

控制输出精度 - 未指定 fixed 或 scientific 控制输出精度 - 指定 fixed 控制输出精度 - 指定 scientific

输出到二进制文件

二进制文件流

在 ofstream 构造函数中使用模式参数指定二进制输出模式;以通常方式构造流,然后在文件打开后使用 setmode 成员函数更改模式;通过二进制文件输出流对象完成输出。

1
2
3
4
5
6
7
8
9
10
11
12
#include <fstream>
using namespace std;
struct Date {
int mon, 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;
}

write 函数在遇到空字符时不会停止,因此可以写入完整的类结构。此函数接受两个参数:一个 char 指针(实际地址)和要写入的字节数。注意需要使用 reinterpret_cast 显式将对象的地址转换为 char * 类型。

输出到字符串

使用字符串作为输出流的目标可以实现将其他数据类型转换为字符串的功能。

字符串输出流 (ostringstream)

用于构造字符串。

函数: * 支持 ofstream 类的所有操作,除了 open 和 close。 * str 函数可以返回当前构造的字符串。

典型应用 * 将数值转换为字符串。

使用 ostringstream 将数值转换为字符串

输入流

重要的输入流类: * istream 类最适合顺序文本模式输入。cin 是它的实例。 * ifstream 类支持磁盘文件输入。 * istringstream。

构造输入流对象

  • 如果在构造函数中指定了文件名,则在构造对象时会自动打开文件。
    1
    ifstream myFile("filename");
  • 使用 open 函数在调用默认构造函数后打开文件。
    1
    2
    ifstream myFile; //创建一个文件流对象
    myFile.open("filename"); //打开文件 "filename"
  • 打开文件时可以指定模式。
    1
    ifstream myFile("filename", ios_base::in | ios_base::binary);

使用提取运算符从文本文件输入

提取运算符 (>>) 为所有标准 C++ 数据类型预设计。它是从输入流对象获取字节的最简单方法。ios 类中的许多操纵符可以应用于输入流。但只有少数对输入流对象有实际影响,最重要的是基操纵符 dec、oct 和 hex。

输入流相关函数

  • open 函数将流与特定磁盘文件关联。
  • get 函数与提取运算符 (>>) 非常相似,主要区别在于 get 函数在读取数据时包括空白字符。(在第 6 章介绍)
  • getline 函数从输入流中读取多个字符,并允许指定输入终止字符。读取完成后,终止字符从读取内容中移除。(在第 6 章介绍)
  • read 成员函数从文件读取字节到指定内存区域,长度参数确定要读取的字节数。在文本模式文件中,读取在遇到文件结束或文件结束标记字符时结束。
  • seekg 函数用于设置文件输入流中读取数据的位置指针。
  • tellg 函数返回文件读取指针的当前位置。
  • close 函数关闭与文件输入流关联的磁盘文件。

示例

从文件读取二进制记录到结构 使用 seekg 函数设置位置指针 读取文件并显示其中 0 元素的位置

从字符串输入 (istringstream)

用于从字符串读取数据,在构造函数中设置要读取的字符串。

函数 * 支持 ifstream 类的所有操作,除了 open 和 close。

典型应用 * 将字符串转换为数值。

输入/输出流

两个重要的输入/输出流

一个 iostream 对象可以是数据的源或目的地。 * 两个重要的 I/O 流类是从 iostream 派生的:fstream 和 stringstream。 * 这些类继承了前面描述的 istream 和 ostream 类的功能。

fstream 类

fstream 类支持磁盘文件的输入和输出。 * 如果需要在同一程序中从特定磁盘文件读取和写入,可以构造一个 fstream 对象。 * 一个 fstream 对象是一个单一流,具有两个逻辑子流,一个用于输入,另一个用于输出。

stringstream 类

stringstream 类支持面向字符串的输入和输出。 * 可用于对同一字符串内容进行交替的读写操作,也由两个逻辑子流组成。

综合示例 - 个人银行账户管理

点击查看源代码