[note]C++ I/O机制与流总结

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

瞬时性算子仅有setwwidth
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 功能是从输入流中读取多个字符,并且允许指定输入终止字符,读取完成后,从读取的内容中删除终止字符。即左闭右开。

输入流操纵算子

noskipwsskipws用于控制是否跳过空格包括’ ', 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
}

其他的字符串输入函数

易混:getlinecin.getline()函数的区别在这里插入图片描述
cin.getline()仍然是成员函数,getline或许才是真正意义上的string配套输入。前者具有C数组风格。
在这里插入图片描述
在这里插入图片描述

双向文件流fstream和双向stringstream

内容在以下的综合实例当中用到。

综合实例

这个FLTK lab,完全实战了各种流类输入包括重定向。

小结

利用主要的三种I/O流,我们可以达成以下几个目的:

  • 能够将数据持久化。
  • 能够处理文本文件和二进制文件。
  • 能够利用字符串流进行字符串与其他类型之间的转换
原创文章 42 获赞 17 访问量 1524

猜你喜欢

转载自blog.csdn.net/weixin_45502929/article/details/105461023