C++ 流、缓冲区

一,流的概念

     C++ 中流是一种数据的载体,通过它可以实现数据的交换和传输。就像水流是一串水组成,人流是一群人组成,C++的数据流就是由一串数据组成的东西。

二,输入流与输出流

    C++ 中 数据从程序流向屏幕或磁盘文件,称为输出流;从磁盘文件或键盘流入到程序中,称为输入流。

三,流分类

  • 标准(控制台流)I/O流:对标准输入设备-键盘   或者标准输出设备-显示器   进行输入、输出操作  
  • 文件I/O流:对外存(磁盘)上的文件进行输入、输出操作。  
  • 字符串I/O流:对内存中指定的字符串存储空间进行输、输出操作  

四,预定义流

C++ 中四个已预先定义好的流对象,以便用户直接使用。

  • istream <- std::cin std::wcin ,对应标准输入的输入流;
  • ostream <- std::cout std::wcout ,对应标准输出的输出流;
  • ostream <- std::cerr std::wcerr ,对应标准错误的输出流。
  • clog:标准错误信息,带有缓冲区的输出。

五,缓冲区

(1),定义:

缓冲区是指用作中介的内存块.

(2),为什么要有缓冲区

为什么要有缓冲区,而不是与相关的文件/设备进行直接的读写操作。提出这个问题是很显然的。这是因为任何决定都是一种在代价和收益中的权衡。考虑到加上缓冲区是有代价的(代码变得更加复杂、需要控制的内容增多),所以加上缓冲区必然有随之而来的收益。众所周知,相对于 CPU 的指令执行和主存访问,I/O 操作是非常慢的。这也就是说,在不考虑缓冲区的情况下,如果程序有频繁的 I/O 操作,那么相当于程序的「高速」部分就会被频繁打断。这对于程序的整体性能是不利的。有了缓冲区,程序就可以避免频繁的 I/O 操作,而是对缓冲区进行读写,只有在必须的情况下,才通过刷新缓冲区进行真实的 I/O 操作。这样一来,程序就能将多个缓慢的 I/O 操作合并成一个,从而在整体上提高了程序的性能。

因此,问题的答案是:使用缓冲区有助于提高程序的整体性能。

 (3),刷新缓冲区

一般来说,有以下几种操作会刷新缓冲区

  • cout被析构
  • 缓冲区满
  • 使用操纵符主动刷新,例如endl,fflush
  • 使用unitbuf操纵符设置流的内部状态,使得每次向流中插入字符都会刷新流
  • 使用cin读取字符串
  • 程序正常结束,作为 main() 函数的 return 操作的一部分,缓冲刷新被执行。

注:

  • flush 和 ends。flush 刷新缓冲区,但不输出任何额外的字符;
  • ends向缓冲区插入一个空字符,然后刷新缓冲区。
cout << unitbuf;  //所有输出操作后都会立即刷新缓冲区
//任何输出都立即刷新,无缓冲
cout << nounitbuf;  //回到正常的缓冲方式

如果想在每次输出操作后都刷新缓冲区,我们可以使用 unitbuf 操作符,它告诉流在接下来的每次写操作之后都进行一次 flush 操作。而 nounitbuf 操作符则重置流, 使其恢复使用正常的系统管理的缓冲区刷新机制:

cout << unitbuf;  //所有输出操作后都会立即刷新缓冲区
//任何输出都立即刷新,无缓冲
cout << nounitbuf;  //回到正常的缓冲方式

六,文件流操作

文件流是以外存文件为输入输出对象的数据流

#include "stdafx.h"
#include <fstream>
#include <iostream>
using namespace std;

int main()
{
	char data[100];

	// 以写模式打开文件
	ofstream outfile;
	outfile.open("afile.dat");

	cout << "Writing to the file" << endl;
	cout << "Enter your name: ";
	cin.getline(data, 100);

	// 向文件写入用户输入的数据
	outfile << data << endl;

	cout << "Enter your age: ";
	cin >> data;
	cin.ignore();

	// 再次向文件写入用户输入的数据
	outfile << data << endl;

	// 关闭打开的文件
	outfile.close();

	// 以读模式打开文件
	ifstream infile;
	infile.open("afile.dat");

	cout << "Reading from the file" << endl;
	infile >> data;

	// 在屏幕上写入数据
	cout << data << endl;

	// 再次从文件读取数据,并显示它
	infile >> data;
	cout << data << endl;

	// 关闭打开的文件
	infile.close();

	return 0;
}

七,字符串流操作

字符串流不是以外存文件为输入输出的对象,而以内存中用户定义的字符数组(字符串)为输入输出的对象,即将数据输出到内存中的字符数组,或者从字符数组(字符串)将数据读入。字符串流也称为内存流。在字符数组中可以存放字符,也可以存放整数、浮点数以及其他类型的数据。

例1:将一组数据保存在字符数组中

#include "stdafx.h"
#include <strstream>
#include <iostream>
using namespace std;
struct student
{
	int num;
	char name[20];
	float score;
};
int main()
{
	student stud[3] = { 1001,"Li",78,1002,"Wang",89.5,1004,"Fun",90 };
	char c[50];  //用户定义的字符数组
	ostrstream strout(c, 30);  //建立输出字符串流,与数组c建立关联,缓冲区长
	for (int i = 0; i<3; i++)  //向字符数组c写个学生的数据
		strout << stud[i].num << stud[i].name << stud[i].score;
	strout << ends;  //ends是C++的I/O操作符,插入一个'\\0'
	cout << "array c:" << c << endl;  //显示字符数组c中的字符
}

运行时在显示器上的输出如下:
array c:
1001Li781002Wang89.51004Fun90

例2:在一个字符数组c中存放几个整数,以空格相间隔,要求将它们放到整型数组中,再按大小排序,然后再存放回字符数组c中。

#include "stdafx.h"
#include <strstream>
#include <iostream>
using namespace std;

int main()
{
	char c[50] = "12 34 65 -23 -32 33 61 99 321 32";
	int a[10], i, j, t;
	cout << "array c:" << c << endl;  //显示字符数组中的字符串
	istrstream strin(c, sizeof(c));  //建立输入串流对象strin并与字符数组c关联
	for (i = 0; i<10; i++)
		strin >> a[i];  //从字符数组c读入个整数赋给整型数组a
	cout << "array a:";
	for (i = 0; i<10; i++)
		cout << a[i] << " ";  //显示整型数组a各元素
	cout << endl;
	for (i = 0; i<9; i++)  //用冒泡法对数组a排序
		for (j = 0; j<9 - i; j++)
			if (a[j]>a[j + 1])
			{
				t = a[j]; a[j] = a[j + 1]; a[j + 1] = t;
			}
	ostrstream strout(c, sizeof(c));  //建立输出串流对象strout并与字符数组c关联
	for (i = 0; i<10; i++)
		strout << a[i] << " ";  //将个整数存放在字符数组c
	strout << ends;  //加入'\\0'
	cout << "array c:" << c << endl;  //显示字符数组c
	return 0;
}

对字符串流的几点说明:
1) 用字符串流时不需要打开和关闭文件。

2) 通过字符串流从字符数组读数据就如同从键盘读数据一样,可以从字符数组读入字符数据,也可以读入整数、浮点数或其他类型数据。如果不用字符串流,只能从字符数组逐个访问字符,而不能按其他类型的数据形式读取数据。这是用字符串流访问字符数组的优点,使用方便灵活。

3) 程序中先后建立了两个字符串流strin和strout,与字符数组c关联。strin从字符数组c中获取数据,strout将数据传送给字符数组。分别对同一字符数组进行操作。甚至可以对字符数组交叉进行读写,输入字符串流和输出字符串流分别有流指针指示当前位 置,互不干扰。

4) 用输出字符串流向字符数组c写数据时,是从数组的首地址开始的,因此更新了 数组的内容。

5) 字符串流关联的字符数组并不一定是专为字符串流而定义的数组,它与一般的字符数组无异,可以对该数组进行其他各种操作。

通过以上对字符串流的介绍,大家可以看到:与字符串流关联的字符数组相当于内存中的临时仓库,可以用来存放各种类型的数据(以ASCII形式存放),在需要时再从中读回来。它的用法相当于标准设备(显示器与键盘),但标准设备不能保存数据,而字符数组中的内容可以随时用ASCII字符输出。它比外存文件使用方便,不必建立文件(不 需打开与关闭),存取速度快。但它的生命周期与其所在的模块(如主函数)相同,该模块的生命周期结束后,字符数组也不存在了。因此只能作为临时的存储空间。

参考:https://zhidao.baidu.com/question/306393691035204004.html

https://www.cnblogs.com/polly333/p/4705664.html

http://ju.outofmemory.cn/entry/338567

https://www.cnblogs.com/l2017/p/7689789.html

http://c.biancheng.net/view/3766.html

https://www.runoob.com/cplusplus/cpp-files-streams.html

http://c.biancheng.net/cpp/biancheng/view/261.html

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

土拨鼠不是老鼠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值