【C++面向对象程序设计】CH7 输入输出流

目录

一、前言

二、标准输出流

1.流对象

(1)cout流对象

(2)cerr流对象

(3)【例7.1】编写程序,从键盘输入a,b,c的值求解一元二次方程。如果a=0或判别式的值<0,输出出错信息

 (4)clog流对象

2.格式输出

(1)用控制符设置输出格式

(2)【例7.2】用控制符控制输出格式

 (3)用流对象的成员函数控制输出格式

(4)用流控制成员函数输出数据

3.用流成员函数put输出字符

(1)介绍

(2)【例7.4】按相反的顺序输出“BASIC”

三、标准输入流

1.cin流

2.【例7.5】测试cin的值,判断流对象的状态

3.输入字符的流成员函数

(1)用get函数读入一个字符

(2)【例7.6】用get函数读入字符

(3)带一个参数的get函数

(4)【例7.6.2】把【例7.6】改写如下

(5)带三个参数的get函数

(6)【例7.6.3】

(7)用成员函数getline读入一行字符

(8)【例7.7】用成员函数getline读入一行字符

3.istream类其他函数

(1)eof()函数

(2)【例7.8】从键盘输入字符串,以文件结束符作为结束标志,逐个输出非空格字符

四、文件操作和文件流

1.文件的概念

2.文件流类与文件流对象

3.文件的打开与关闭

(1)打开磁盘文件

 (2)关闭磁盘文件

4.对ASCII码文件操作

(1)【例7.11】定义一个有十个元素的整形数组,从键盘输入十个整数,将他们放入数组,同时用插入运算符将他们写入当前目录下的f1.txt文件。

(2)【例7.12】从【例7.11】建立的f1.txt文件中读取10个整数放入数组中,找出并输出最大数和它的下标值

(3)【例7.13】从键盘读入一行字符,把其中的个字母字符存放到磁盘文件f2.txt中。再从f2.txt读入数据,把其中的小写字母改写为大写字母并存入磁盘文件f3.txt。

5.对二进制文件操作

(1)介绍

(2)【例7.14】把一批数据以二进制形式写入磁盘文件

(3)【例7.15】从【例7.14】产生的文件中读数据并显示到屏幕上

(4)与文件指针有关的流成员函数

(5)随机访问二进制数据文件

五、字符串流

1.建立写字符串流对象

2.建立读取字符串流对象 

3.【例7.17】

4.【例7.18】在一个字符数组c中存放10个整数,以空格为分隔符,要求将它们放到整形数组中排升序,然后再写入原来的字符数组中。


一、前言

        在C++中,输入输出是通过流完成的。C++的输出操作将一个对象的状态转化成一个字符序列,输出到某个地方。输入操作则是从某个地方接收一个字符序列,然后将其转换车一个对象的状态所要求的格式。

        把接收存放输出数据的地方叫做目标,把输入数据来自的地方叫做源,输入和输出操作可以看成字符序列在源、目标和对象之间的流动。C++把与输入和输出有关的操作定义为一个类体系,放在一个系统库里,供用户调用。

        这个执行输入和输出操作的类体系叫做流类,提供流类实现的系统叫做流类库。

【C++面向对象程序设计】CH7 输入输出流_第1张图片

        此图是简化的流类库的基本类等级图,而不是直接的继承关系图。其实它们都是模板类,箭头表示的是类等级关系。

        这个等级关系在头文件iostream.h中说明。在图中,ios类中一个指针成员指向streambuf类的对象。Streambuf类管理流的缓冲区。由于数据隐蔽和封装的需要,普通用户只使用ios、istream和ostream类提供的公有接口,完成流的提取和插入操作。ios类是istream类和ostream类的虚基类,提供对流的格式化I/O操作和错误处理的成员处理的成员函数。从ios类共有派生istream类和ostream类分别提供对流进行提取和插入操作的成员函数,而iostream类通过组合istream类和ostream类支持对一个流进行双向操作,他并没有提供新成员函数。

        iostream中预定义四个流对象,它们分别是cin、cout、cerr、clog。事实上可以将cin视为istream的一个对象,而cout视为ostream的一个对象。流是一个抽象的概念,当实际进行I/O操作时,必须将流和一个具体的物理设备连接起来。

        C++的流类库预定义的四个流所连接的设备如表所示:

【C++面向对象程序设计】CH7 输入输出流_第2张图片

        与iostream类库有关的头文件:

        iostream类库中不同的类的声明被放在不同的头文件中,用户在程序中用#include命令包含所需的头文件就相当于在程序中声明了所需的类。

iostream                输入输出流操作

fstream                  管理文件的I/O操作

strstream               字符流的I/O操作

stdiostream            混合使用C和C++

iomanip                  使用格式化I/O操作

        在iostream头文件中重载了>>和<<运算符。用于标准类型数据的输入和输出。

二、标准输出流

1.流对象

        标准输出流是流向标准输出设备的数据。

        ostream类定义了cout、cerr和clog三个流对象。

(1)cout流对象

        cout流在内存开辟一个缓冲区存放流中的数据,当遇到endl时,立即输出流中的所有数据,然后插入一个换行符并清空缓冲区。

(2)cerr流对象

        cerr流对象是标准出错流。它向标准出错设备输出有关出错的信息。

(3)【例7.1】编写程序,从键盘输入a,b,c的值求解一元二次方程。如果a=0或判别式的值<0,输出出错信息

  • NS流程图

【C++面向对象程序设计】CH7 输入输出流_第3张图片

  • 代码

#include 
#include 
using namespace std;

int main() 
{
	float  a, b, c, disc;
	cout << "请输入 a,b,c:";
	cin >> a >> b >> c;
	if (a == 0)
		cerr << "a 等于0,错误!" << endl;
	else if ((disc = b * b - 4 * a * c) < 0)
		cerr << "判别式b*b-4*a*c<0" << endl;
	else 
	{
		cout << "x1=" << (-b + sqrt(disc)) / (2 * a) << endl;
		cout << "x2=" << (-b - sqrt(disc)) / (2 * a) << endl;
	}
	return 0;
}
  • 结果

【C++面向对象程序设计】CH7 输入输出流_第4张图片

 (4)clog流对象

        clog流对象也是标准出错流,它与cerr的区别是,cerr不经过缓冲区直接向显示器输出出错信息,clog把出错信息存放在缓冲区,当缓冲区满或遇到endl时向显示器输出出错的信息。

2.格式输出

        在输出数据时,如不指定格式,则采用系统给定的默认格式。可以通过控制符或流的成员函数设置输出格式。

(1)用控制符设置输出格式

        下表列出了输出格式的控制符。这些控制符在头文件iomanip中定义。

【C++面向对象程序设计】CH7 输入输出流_第5张图片

(2)【例7.2】用控制符控制输出格式

  • 代码
#include 
#include 
using namespace std;

int main() {
	int a;
	cout << "input a:";
	cin >> a;
	cout << "dec:" << dec << a << endl;
	cout << "hex:" << hex << a << endl;
	cout << "oct:" << setbase(8) << a << endl;
	char *pt = "China";
	cout << setw(10) << pt << endl;
	cout << setfill('*') << setw(10) << pt << endl;
	double pi = 22.0 / 7.0;
	cout << setiosflags(ios::scientific) << setprecision(8) ;
	cout << "pi=" << pi << endl;
	cout << "pi=" << setprecision(4) << pi << endl;
	cout << "pi=" << setiosflags(ios::fixed) << pi << endl;
	return 0;
}
  • 结果

【C++面向对象程序设计】CH7 输入输出流_第6张图片

 (3)用流对象的成员函数控制输出格式

        用于控制输出格式的常用成员函数如下。

【C++面向对象程序设计】CH7 输入输出流_第7张图片

        流成员函数setf和控制符setiosflags括号中参数是格式标志,在类ios中定义它是枚举值。所以在引用这些格式标志时要以ios::开始,格式标志列于表7.5。

【C++面向对象程序设计】CH7 输入输出流_第8张图片

(4)用流控制成员函数输出数据

#include 
using namespace std;

int main() 
{
	int a = 21;
	cout.setf(ios::showbase);
	cout << "dec:" << a << endl;
	cout.unsetf(ios::dec);
	cout.setf(ios::hex);
	cout << "hex:" << a << endl;
	cout.unsetf(ios::hex);
	cout.setf(ios::oct);
	cout << "oct:" << a << endl;
	char *pt = "China";
	cout.width(10);
	cout << pt << endl;
	cout.width(10);
	cout.fill('*');
	cout << pt << endl;
	double pi = 22.0 / 7.0;
	cout.setf(ios::scientific);
	cout << "pi=";
	cout.width(14);
	cout << pi << endl;
	cout.unsetf(ios::scientific);
	cout.setf(ios::fixed);
	cout.width(12);
	cout.setf(ios::showpos);
	cout.setf(ios::internal);
	cout.precision(6);
	cout << pi << endl;
	return 0;
}

【C++面向对象程序设计】CH7 输入输出流_第9张图片

         前面的【例7.2】和【例7.3】分别用控制符和流成员函数设置输出流中的数据基数,虽然它们的功能相似,但是还是有区别的:

  • 用控制符设置输出流的数据基数后,这个设置会一直保留到下一次的设置
  • 用成员函数srtf()设置的格式,必须用函数unsetf()终止后才能重新设置,并且函数setf()设置的基数仅仅在本次输出流中生效,之后无论是否用函数unsetf()终止,下次输出流数据又以默认的十进制基数显示

3.用流成员函数put输出字符

(1)介绍

        格式:

cout.put(字符/数字)[.put(…) ……]

         如果是字符,直接输出该字符;如果是数字,可以用八进制、十进制或十六进制表示整数,用该数字对256取模,输出对应的ASCII码字符。

(2)【例7.4】按相反的顺序输出“BASIC”

#include 
using namespace std;

int main() 
{
	char *a = "BASIC";
	for (int i = 4; i >= 0; i--)
		cout.put(*(a + i));
	cout.put('\n');
	return 0;
}

三、标准输入流

1.cin流

        cin是istream类的对象,从标准输入设备读取数据。利用提取运算符>>在流中提取数据时通常跳过流中的空格、tab键、换行符等字符。只有输入回车键时输入的数据才进入键盘缓冲区,形成输入流,提取运算符才能从其中提取数据。

        当遇到无效字符(与变量数据类型不一致)或文件结束符时,输入流cin就处于出错状态,此时对cin流的所有操作都被终止。当输入流出错时,cin的值是false,所以可以根据cin的值判断流对象是否处于正常状态。

2.【例7.5】测试cin的值,判断流对象的状态

#include 
using namespace std;

int main() 
{
	float grade;
	cout << "enter grade:";
	while (cin >> grade) 
	{
		if (grade >= 85)
			cout << grade << " GOOD!" << endl;
		if (grade < 60)
			cout << grade << " fail!" << endl;
		cout << "enter grade:";
	}
	cout << "The end." << endl;
	return 0;
}

【C++面向对象程序设计】CH7 输入输出流_第10张图片

3.输入字符的流成员函数

(1)用get函数读入一个字符

        格式:cin.get()

        函数的类型是字符,函数的功能是从输入流中提去一个字符作为函数值返回。如在流中遇到文件结束符EOF时,返回-1。

(2)【例7.6】用get函数读入字符

#include 
using namespace std;

int main() 
{
	char c;
	cout << "enter a sentence:" << endl;
	while ((c = cin.get()) != EOF)
		cout.put(c);
	return 0;
}

【C++面向对象程序设计】CH7 输入输出流_第11张图片

(3)带一个参数的get函数

        格式:cin.get(字符变量)

        功能:从输入流中提取一个字符赋予字符变量。如遇到文件结束符就结束提取。输入回车后再输入文件结束符。

(4)【例7.6.2】把【例7.6】改写如下

#include 
using namespace std;

int main() 
{
	char c;
	cout << "enter a sentence:" << endl;
	while (cin.get(c)) 
    {
		cout.put(c);
	}
	cout << "end" << endl;
	return 0;
}

【C++面向对象程序设计】CH7 输入输出流_第12张图片

(5)带三个参数的get函数

        格式:cin.get(字符指针,n,终止字符)

        n与提取的字符个数相关。函数从键盘缓冲区最多顺序提起n-1个字符,顺序放入字符指针所指的字符数组。如果在提取过程中遇到终止字符,无论是否满足指定的字符个数都要终止提取。

(6)【例7.6.3】

#include 
using namespace std;

int main() 
{
	char ch[20];
	cout << "enter a sentence:" << endl;
	cin.get(ch, 10, '\n');
	cout << ch << endl;
	return 0;
}

【C++面向对象程序设计】CH7 输入输出流_第13张图片

        cin.get()中不带参数和只带一个参数的函数,都是以文件结束符作为终止提取的控制符。如提取一个字符结束时会把指针移到下一个字符。

        cin.get()中带三个参数的函数,以字符个数或指定终止提取字符为终止提取的控制符。如提取字符结束不会把指针移到下一个字符。

        cin.get()函数族不忽略提取的空白字符。

(7)用成员函数getline读入一行字符

        格式:cin.getline(字符指针,n,终止字符)

        函数功能与带三个参数的get函数类似。

        带三个参数的cin.get和cin.getline相同的是它们都不忽略提取过程中遇到的空白字符,当遇到终止字符时就停止提取。

        带三个参数的cin.get和cin.getline不同的是停止提取时,cin.getline会把指针移到终止字符后相邻的字节,而带三个参数的cin.get函数不会。

#include 
using namespace std;

int main(int argc, char *argv[]) 
{
	char ch[20];
	char c1;
	cout << "输入一句话:" << endl;
	cin >> ch;
	cout << "第一次 cin 提取的字符串是:" << ch << endl;
	c1 = cin.get();
	cout << "第二次 cin.get() 提取的字符串是:" << c1 << endl;
	cin.get(c1);
	cout << "第三次 cin.get(c1) 提取的字符串是:" << c1 << endl;
	cin.get( ch, 20, '/');
	cout << "第四次 cin.get( ch, 20, '/') 提取的字符串是:" << ch << endl;
	cin.getline(ch, 20, '/');
	cout << "第五次 cin.getline (ch,20,'/')提取的字符串是:" << ch << endl;
	cin.getline(ch, 20, '/');
	cout << "第六次 cin.getline (ch,20,'/')提取的字符串是:" << ch << endl;
	return 0;
}

【C++面向对象程序设计】CH7 输入输出流_第14张图片

        cin和cin.getline都具有从键盘缓冲区按指针所指提取字符串的功能。它们有以下区别:

  •  cin忽略起始的空白字符;而cin.getline不忽略起始的空白字符
  • cin当提取到非空白字符后,遇到空白字符时就终止提取,指针就停留在空白字符处;而cin.getline是提取到规定的终止字符或规定的字符个数后终止提取,指针停留在提取的最后一个字符后面相邻的字节
  • 通过对>>的重载,cin可以提取其他类型的数据;而cin.getline只能输入字符串

(8)【例7.7】用成员函数getline读入一行字符

#include 
using namespace std;

int main() 
{
	char ch[20];
	cout << "输入一句话:" << endl;
	cin >> ch;
	cout << "第一次 cin 提取的字符串是:" << ch << endl;
	cin.getline(ch, 20, '/');
	cout << "第二次 cin.getline 提取的字符串是:"  << ch << endl;
	cin.getline(ch, 20);
	cout << "第三次 cin.getline 提取的字符串是:" << ch << endl;
	return 0;
}

【C++面向对象程序设计】CH7 输入输出流_第15张图片

#include 
using namespace std;

int main() 
{
	char ch[20];
	cout << "输入一句话:" << endl;
	cin >> ch;
	cout << "第一次 cin 提取的字符串是:" << ch << endl;
	cin.get( ch, 20, '/');
	cout << "第二次 cin.get 提取的字符串是:"  << ch << endl;
	cin.getline(ch, 20);
	cout << "第三次 cin.getline 提取的字符串是:" << ch << endl;
	return 0;
}

【C++面向对象程序设计】CH7 输入输出流_第16张图片

【C++面向对象程序设计】CH7 输入输出流_第17张图片

3.istream类其他函数

(1)eof()函数

        当输入缓冲区的指针遇到文件结束符时函数值为真,否则为假。从键盘用ctrl+z输入文件结束符

(2)【例7.8】从键盘输入字符串,以文件结束符作为结束标志,逐个输出非空格字符

#include 
using namespace std;

int main() 
{
	char c;
	while (!cin.eof())
		if ((c = cin.get()) != '  ')
			//cout.put(c);
			cout << c ;
	return 0;
}

【C++面向对象程序设计】CH7 输入输出流_第18张图片

四、文件操作和文件流

1.文件的概念

        文件是指存储在存储介质上的数据集合。操作系统把存储介质上的相关数据抽象为文件,用标识符为其取名并由文件系统管理文件。只要用户指出文件名,操作系统就可以按名存取文件信息。

        根据文件中数据的表现形式,文件分为ASCII文件和二进制文件。ASCII文件就是文本文件,每个字节表示一个字符。二进制文件是把内存中的数据、指令按其在内存的格式存放在磁盘上。

        字符信息在内存也是以ASCII码形式存放,所以字符在ASCII码文件和在二进制文件中形式是一样的。对于数值数据,两者是不一样的。

        例如,一个十进制长整数100000,用二进制表示时用四个字节;而用ASCII表示时用六个字节。

【C++面向对象程序设计】CH7 输入输出流_第19张图片

2.文件流类与文件流对象

        文件流是以外存文件为输入输出对象的数据流。输出文件流是从内存流向外存文件的数据流,输入文件流是从外存文件流向内存的数据流。为了弥补访问内存和访问外村的速度差,每个文件流都有一个内存缓冲区。

        在C++的I/O类库里定义了几种文件类,专门用于文件的输入和输出操作。

【C++面向对象程序设计】CH7 输入输出流_第20张图片

        从图中可以看到C++从标准输入、输出流类派生出三个文件流类。

        ifstream类,支持从磁盘文件输入。

        ofstream类,支持向磁盘文件输出。

        fstream类,支持对磁盘文件输入和输出。

        要对文件进行输入输出,必须定义一个文件流类对象,用对象调用类的成员函数对文件操作。

3.文件的打开与关闭

(1)打开磁盘文件

         打开文件是指在读写文件前做必要的准备工作,包括:

  • 在文件流对象和磁盘文件之间建立关联
  • 指定文件的格式和操作方式

        打开文件有两种方法

1)建立文件流对象,用对象调用类成员函数open

ofstream  outfile;
       outfile.open( “f1.txt”, ios::out);

        调用成员函数的一般形式为:

文件流对象.open(文件名,输入输出方式);

        文件名可以包括路径,如省略路径,默认文件在当前目录(工程文件目录)。

        输入输出方式在ios类中定义,它们是枚举常量,有多种选择。表7.6列出了文件输入输出方式设置值。

2)在定义文件流对象时指定参数

文件流类  对象(文件名,输入输出方式);

         例:

ofstream  outfile ( “f1.txt”, ios::out);

        打开文件操作可能成功也可能失败,可以测试文件流对象判定。文件流对象是真,表示成功;否则表示失败。

【C++面向对象程序设计】CH7 输入输出流_第21张图片

 (2)关闭磁盘文件

        文件使用结束,必须关闭文件,用文件流对象调用关闭文件成员函数实现。

        格式:文件流对象.close();

        功能:解除文件流对象与磁盘文件的关联

4.对ASCII码文件操作

        ASCII码文件也是文本文件,文件中一个字节存放一个字符。对ASCII码文件操作包括向文件写入字符和从文件读取字符。

        读写ASCII码文件有用文件流对象与提取、插入运算符和用文件流对象调用类的成员函数put,get,getline两种方法。

(1)【例7.11】定义一个有十个元素的整形数组,从键盘输入十个整数,将他们放入数组,同时用插入运算符将他们写入当前目录下的f1.txt文件。

【C++面向对象程序设计】CH7 输入输出流_第22张图片

#include 
using namespace std;

int main() 
{
	int a[10];
	ofstream outfile("D:\个人成长\学业\课程\c++\f1.txt");
	if (!outfile) 
	{
		cerr << "open error!" << endl;
		exit(1);
	}
	cout << "enter 10 integer numbers:" << endl;
	for (int i = 0; i < 10; i++) 
	{
		cin >> a[i];
		outfile << a[i] << " ";
	}
	outfile.close();
	return 0;
}

【C++面向对象程序设计】CH7 输入输出流_第23张图片

         程序中用文件流类ofstream,它是在头文件fstream中定义的,用vc6.0时要把这个头文件包含进来。

        建立输出流对象默认就是向文件输出,所以对文件的操作方式可以省略。

        对文本文件写数值数据时,两个数据之间要用空格或换行符隔开,便于读文件。

(2)【例7.12】从【例7.11】建立的f1.txt文件中读取10个整数放入数组中,找出并输出最大数和它的下标值

【C++面向对象程序设计】CH7 输入输出流_第24张图片

【C++面向对象程序设计】CH7 输入输出流_第25张图片

        对程序分析从顶到下,逐步细化。这是结构化程序设计的基本功。前面分析中先设计出一个大框架,然后再把不能用语句表示的功能细化成能用语句组合表示的功能。

#include 
using namespace std;

int main() 
{
	int a[10], max, i, order;
	ifstream infile("f1.txt", ios::in);
	if (!infile) 
	{
		cerr << "open error!" << endl;
		exit(1);
	}
	for (i = 0; i < 10; i++) 
	{
		infile >> a[i];
		cout << a[i] << " ";
	}
	cout << endl;
	infile.close();
	max = a[0];
	order = 0;
	for (i = 1; i < 10; i++)
		if (a[i] > max) 
		{
			max = a[i];
			order = i;
		}
	cout << "max=" << max << endl << "order=" << order << endl;
	return 0;
}

【C++面向对象程序设计】CH7 输入输出流_第26张图片

(3)【例7.13】从键盘读入一行字符,把其中的个字母字符存放到磁盘文件f2.txt中。再从f2.txt读入数据,把其中的小写字母改写为大写字母并存入磁盘文件f3.txt。

分析:程序中使用两个文件,其中f2先做输出文件(写入字母),再做输入文件(读取字母),f3做输出文件(写入大写字母)

【C++面向对象程序设计】CH7 输入输出流_第27张图片

#include 
using namespace std;

void save_to_file() 
{ // 写文件
	ofstream outfile("f2.txt");
	if (!outfile) 
	{
		cerr << "open f2.txt error!" << endl;
		exit(1);
	}
	char c[80];
	cin.getline(c, 80);
	for (int i = 0; c[i] != 0; i++)
		if ( c[i] >= 65 && c[i] <= 90 || c[i] >= 97 && c[i] <= 122) 
		{
			outfile << (c[i]);
			cout << c[i];
		}
	cout << endl;
	outfile.close();
}

void get_from_file() 
{
	char ch;
	ifstream infile("f2.txt", ios::in);
	if (!infile) 
	{
		cerr << "open f2.txt error!" << endl;
		exit(1);
	}
	ofstream outfile("f3.txt");
	if (!outfile) 
	{
		cerr << "open f3.txt error!" << endl;
		exit(1);
	}

	while (infile.get(ch)) 
	{
		if (ch >= 97 && ch <= 122)
			ch = ch - 32;
		outfile << ch;
		cout << ch;
	}
	cout << endl;
	infile.close();
	outfile.close();
}

int main() 
{
	save_to_file();
	get_from_file();
	return 0;
}

【C++面向对象程序设计】CH7 输入输出流_第28张图片

#include 
//专门设计的读文件程序
#include 
using namespace std;

void display_file(char *filename) 
{
	ifstream infile(filename, ios::in);
	if (!infile) 
	{
		cerr << "open error!" << endl;
		exit(1);
	}
	char ch;
	while (infile.get(ch))
		cout << (ch);
	cout << endl;
	infile.close();
}

int main() 
{
	display_file("f3.txt");
	return 0;
}

【C++面向对象程序设计】CH7 输入输出流_第29张图片

5.对二进制文件操作

(1)介绍

        二进制文件是按内存中的数据存储形式写入磁盘文件,因此又称为内存数据的映象文件。

        对二进制文件操作与对文本文件操作相似的是先定义文件流对象,然后打开文件,使用完要关闭文件。在打开时必须指定文件的存储形式是二进制形式,二进制文件既可以作为输入文件也可以作为输出文件,还可以作为既能输入又能输出的文件。这是与ASCII文件不同的地方。

        分别用成员函数read和write读写文件。

        读二进制文件用istream类read成员函数;写二进制文件用ostream类write成员函数。它们的函数原型分别是:

 istream&read(char * bu, int len);
 ostream&write( const char * bu, int len);

        字符指针bu指向内存要读或写的数据起始位置。len是一次要读写的数据字节个数(数据长度)。调用格式:

输入文件流对象.read( 内存指针, 长度);

输出文件流对象.write( 内存指针, 长度);

(2)【例7.14】把一批数据以二进制形式写入磁盘文件

【C++面向对象程序设计】CH7 输入输出流_第30张图片

#include 
#include 
using namespace std;

struct student 
{
	char name[20];
	int num;
	int age;
	char sex;
};

int main() 
{
	student
	stud[3] = { "Li",   1001, 18, 'f',    "Fun", 1002, 19, 'm',
	            "Wang", 1004, 17, 'f'
	          };
	ofstream outfile("stud.dat", ios::binary);
	if (!outfile) 
	{
		cerr << "open error!" << endl;
		abort();
	}
	outfile.write( (char *)&stud, sizeof(stud));
	outfile.close();
	return 0;
}

(3)【例7.15】从【例7.14】产生的文件中读数据并显示到屏幕上

【分析】从文件读取数据必须先放入内存,所以必须设置一个与文件数据格式相同的数据结构即机结构数组,然后再将结构数组元素逐个输出

【C++面向对象程序设计】CH7 输入输出流_第31张图片

#include 
#include 
using namespace std;

struct student 
{
	char name[20];
	int num;
	int age;
	char sex;
};

int main() 
{
	student stud[3];
	int i;
	ifstream infile("stud.dat", ios::binary);
	if (!infile) 
	{
		cerr << "open error!" << endl;
		abort();
	}
	infile.read((char *)stud, sizeof(stud));
	infile.close();
	for (i = 0; i < 3; i++) 
	{
		cout << "NO." << i + 1 << endl;
		cout << "姓名:" << stud[i].name << endl;
		cout << "学号:" << stud[i].num << endl;
		cout << "年龄:" << stud[i].age << endl;
		cout << "性别:" << stud[i].sex << endl;
	}
	return 0;
}

【C++面向对象程序设计】CH7 输入输出流_第32张图片

(4)与文件指针有关的流成员函数

        为了随机读取二进制文件中数据,磁盘文件用一个指针表示当前要访问的位置。每次读或写文件后会自动修改指针。使指针总是指向当前要访问的位置。对于二进制文件,允许程序控制指针移动,实现随机访问文件。文件流提供了有关文件指针的成员函数。表7.7列出这些函数。

【C++面向对象程序设计】CH7 输入输出流_第33张图片         这些函数名头或尾字母不是g就是p。带g的用于输入,带p的用于输出。对于输入输出文件不区分g和p。

        函数参数文件中的位置和位移量以字节为单位,是长整型。参照位置表示以什么作为移动起点。ios类定义为:

  • ios::beg        以文件开始为起点,这是默认值
  • ios::cur         以指针当前位置为起点
  • ios::end        以文件结尾为起点

        例:

infile.seekg( 100 );
infile.seekg( -50,ios::cur);
outfile.seekp( -75,ios::end);

(5)随机访问二进制数据文件

        利用流类的成员函数移动文件指针,实现随机访问文件中任何一个字节里的数据。

        例,有五个学生的数据,要求:

  • 把它们写入磁盘文件
  • 从磁盘文件读第1,3,5学生数据并显示
  • 从磁盘文件读入修改过的5个学生数据并显示
#include 
using namespace std;

struct student
{  int num;
   char name[20];
   float score;
};
int main()
{
	int i;
	student stud[5]={1001,"Li",85,1002,"Fun",97.5,1004,"Wang",54,
                  1006,"Tan",76.5,1010,"ling",96};
	fstream iofile("stud.dat",ios::in|ios::out|ios::binary);
	if(!iofile)
	{
		cerr<<"open error!"<

五、字符串流

        字符串流以内存中用户定义的字符数组(字符串)为输入输出对象,即将数据写入内存数组,或从内存字符数组读取数据。

        字符串流也需要缓冲区,读取或写入时,流缓冲区中的数据不断增加,待缓冲区满或遇到换行符时,缓冲区中数据一起写入字符数组或赋予指定变量。

1.建立写字符串流对象

        ostrstream类的构造函数原型是:

 ostrstream::ostrstream( char *bu, int n, int mode =ios::out);

        bu是指向字符数组首址的指针,n是指定流缓冲区的长度,第三个参数可忽略,默认是ios::out。

        例:

ostrstream strout( ch1,20);

        建立字符流对象strout,并与字符数组ch1关联(通过字符串流把数据写入字符数组ch1),流缓冲区长度是20个字节。 

2.建立读取字符串流对象 

istrstream::istrstream( char *bu, int n);
istrstream::istrstream( char *bu);

        bu是指向字符数组首址的指针,n是流缓冲区的长度,如没有n,表示缓冲区的长度与字符串数组长度相同。例

istrstream  strin( ch2);
istrstream  strin( ch2, 20);

        第一条语句是建立读取字符串流对象strin,将字符数组ch2所有数据作为读取字符串流的内容。

        第二条语句是建立读取字符串流对象strin,将字符数组ch2前20个字符作为读取字符串流的内容。

3.【例7.17】

#include 
#include 
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);
	for (int i = 0; i < 3; i++)
		strout << stud[i].num << stud[i].name << stud[i].score;
	strout << ends;
	cout << "array c:" << endl << c << endl;
	return 0;
}

4.【例7.18】在一个字符数组c中存放10个整数,以空格为分隔符,要求将它们放到整形数组中排升序,然后再写入原来的字符数组中。

#include 
#include 
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));
	for (i = 0; i < 10; i++)
		strin >> a[i];
	cout << "array a:";
	for (i = 0; i < 10; i++)
		cout << a[i] << " ";
	cout << endl;
	for (i = 0; i < 9; i++)
		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));
	for (i = 0; i < 10; i++)
		strout << a[i] << " ";
	strout << ends;
	cout << "array c:" << c << endl;
	return 0;
}

【C++面向对象程序设计】CH7 输入输出流_第34张图片


你可能感兴趣的:(C++面向对象程序设计,c++,开发语言)