I/O概念和流类库继承关系
(整理自清华郑莉老师,北大郭炜老师MOOC)
程序与外界的信息交换抽象结构
当程序和外界环境进行信息交换时,存在着两个对象:程序、文件。
在C类的语言中,连键盘、控制台都被视作文件。
流
流是一种抽象,负责在数据生产者和消费者之间建立练习,并管理数据的流动。
一般的流操作模型:
- 建立流对象
- 指定流对象和文件对象联系
- 程序对象操作流对象
- 流对象对文件对象产生作用
读操作被称为提取,写操作被称为插入。
流类库结构
流类列表
输入输出流
输出流
重要预定义流
三个预定义流对象:
cout
:标准输出流cerr
:不可重定向,不缓冲。即时输出较为紧急的错误信息clog
:不可重定向,带缓冲。
三个重要输出流:
stream
fstream
stringstream
标准输出换向
ofstream fout("b.out");//from file
streambuf* pOld =cout.rdbuf(fout.rdbuf());//transferred to buffer
cout.rdbuf(pOld);//transferred back to stdout
构造输出流对象
ofstream
支持磁盘文件输出
几种不同的构造方式
//direct constructing
ofstream myfile("filename");
//constructed and then open
myfile.open("filename");
//more output type
ostream myfile("filename", ios::out | ios::app)
文件输出流成员函数的三种类型
与操作符等价的成员函数
open()
:建立流和特定磁盘文件的关联:或需指定打开模式
执行非格式化写操作的成员函数
put()
:将单字符插入输出流write()
:把内存中的整块以二进制插入输出流
其他流成员
seekp()
和tellp()
:操作文件流的内部指针close()
:关闭与一个文件输出流关联的磁盘文件- 错误处理函数
格式化输出与manipulator
瞬时性算子仅有setw
和width
setiosflags()
和resetiosflags()
是对应的一对设定和解除算子。参数为ios::xxx
的流操纵算子。
int n = 141;
//1) 分别以十六进制、十进制、八进制先后输出 n
cout << "1) " << hex << n << " " << dec << n << " " << oct << n << endl;
// 1) 8d 141 215
double x = 1234567.89,y = 12.34567;
//2) 保留5位有效数字
cout << "2) " << setprecision(5) << x << " " << y << " " << endl;
//3) 保留小数点后面5位
cout << "3) " << fixed << setprecision(5) << x << " " << y << endl ;
//4) 科学计数法输出,且保留小数点后面5位
cout << "4) " << scientific << setprecision(5) <<x << " " << y << endl;
// 2) 1.2346e+006 12.346
// 3) 1234567.89000 12.34567
// 4) 1.23457e+006 1.23457e+001
//5) 非负数要显示正号,输出宽度为12字符,宽度不足则用'*'填补
cout << "5) " << showpos << fixed << setw(12) << setfill('*') << 12.1<< endl;
//6) 非负数不显示正号,输出宽度为12字符,宽度不足则右边用填充字符填充
cout << "6) " << noshowpos << setw(12) << left << 12.1 << endl;
//7) 输出宽度为12字符,宽度不足则左边用填充字符填充
cout << "7) " << setw(12) << right << 12.1 << endl;
//8) 宽度不足时,负号和数值分列左右,中间用填充字符填充
cout << "8) " << setw(12) << internal << -12.1 << endl;
//9) setw()函数和cout.width()的作用具有瞬时性,返回正常普通模式输出
cout << "9) " << 12.1 << endl;
// 5) ***+12.10000
// 6) 12.10000****
// 7) ****12.10000
// 8) -***12.10000
// 9) 12.10000
注:除了宽度设置函数,其他都可以在重设之前一直作用。
二进制输出:write
二进制由于不发生数据类型转换,读写效率都较高。在不需要考虑人类阅读时,
write函数的第一个参数是一个C风格的字符串指针。所以在接下来的例子当中用临时的类型转换函数完成调用。
C++自定义对象一般不能整体写入文件。通常可以直接写入的只有结构体类型。因此我们如果要写入一个自定义的简单数据结构,可以有如下的形式:
#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;
}
字符串输出流ostringstream
一般仅用作将其他类型数据转化为字符串。
//11_6.cpp
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
//函数模板toString可以将各种支持“<<“插入符的类型的对象转换为字符串。
template <class T>
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;
}
输出结果:
5
1.2
输入流
由于不涉及多种复杂的格式化,所以输入流的内容在对偶的情形下,大量内容是输出流的真子集。以下只讨论输入流很特别的部分。
输入流成员函数
- get 功能与提取运算符(>>)很相像,主要的不同点是get函数在读入数据时包括空白字符。
- getline 功能是从输入流中读取多个字符,并且允许指定输入终止字符,读取完成后,从读取的内容中删除终止字符。即左闭右开。
输入流操纵算子
noskipws
和skipws
用于控制是否跳过空格包括’ ', tab, 回车。string类自身带有跳过设置,所以使用时会出现一点小问题,如下。另附cplusplus.com的代码示例。
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
int main()
{
string tmp, tmp2, tmp3;
cin >> noskipws >> tmp >> tmp2 >> tmp3; //std::string will automatically skip the whitespace. so the tpm2 and tmp3 are both void
cout << tmp << tmp2 << tmp3 << endl;
cout << tmp.length() << ' ' << tmp2.length() << ' ' << tmp3.length() << endl;
//input: 123 456
//output: 123
// 3 0 0
char a, b, c;
istringstream iss(" 123");
iss >> skipws >> a >> b >> c;
cout << a << b << c << '\n';
iss.seekg(0);
iss >> noskipws >> a >> b >> c;
cout << a << b << c << '\n';
//123
// 1
}
其他的字符串输入函数
易混:getline
和cin.getline()
函数的区别
cin.getline()
仍然是成员函数,getline
或许才是真正意义上的string
配套输入。前者具有C数组风格。
双向文件流fstream
和双向stringstream
内容在以下的综合实例当中用到。
综合实例
这个FLTK lab,完全实战了各种流类输入包括重定向。
小结
利用主要的三种I/O流,我们可以达成以下几个目的:
- 能够将数据持久化。
- 能够处理文本文件和二进制文件。
- 能够利用字符串流进行字符串与其他类型之间的转换