I/O流的概念及流类库的结构

程序建立一个流对象

  • 当程序与外界环境进行信息交换时,存在着两个对象,一个是程序中的对象,另一个是文件对象
  • 流是一种抽象,它负责在数据的生产者数据的消费者之间建立联系,并管理数据的流动。

指定这个流对象与某个文件对象建立连接,程序操作流对象流,对象通过文件系统对所连接的文件对象产生作用。

操作系统是将键盘、屏幕、打印机和通信端口作为扩充文件来处理的,而这种处理是通过操作系统的设备驱动程序来实现的。这些设备与磁盘文件是等同的。

一般意义下的读操作在流数据对象中被称为(从流中)提取,写操作被称为(向流中)插入

I/O流类列表

![](https://pic3.zhimg.com/80/v2-4544fd2b14037c1638862690c745edc2_1440w.png)

输出流

最重要的三个输出流:

  • 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++数据类型预先设计的,用于传送字节到一个输出流对象。

操纵符(manipulator)

插入运算符与操纵符一起工作控制输出格式。

  • 很多操纵符都定义在ios_base类中(如hex())、<iomanip>头文件(如setprecision())。
  • 控制输出宽度:在流中放入setw操纵符或调用width成员函数为每个项指定输出宽度。

setw和width仅影响紧随其后的输出项,但其它流格式操纵符保持有效直到发s生改变。

  • 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类支持面向字符串的输入和输出

  • 可以用于对同一个字符串的内容交替读写,同样是由两个逻辑子流构成。

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

点击查看源代码