一,流的概念
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