1、第第1313章章 文件文件输入输入/输出输出(I/O)I/O):程序与程序与外设之间的数据交换外设之间的数据交换输入:输入:程序从外设接收字程序从外设接收字节序列并转换为指定格式节序列并转换为指定格式数据数据输出:输出:程序将数据转换为程序将数据转换为字节序列输出到外设字节序列输出到外设C+C+语言无专门的语言无专门的I/OI/O语句语句,但其编译系统都提供但其编译系统都提供I/OI/O库,支持库,支持I/OI/O操作操作13.1 13.1 基本概念基本概念13.2 13.2 文件文件13.3 13.3 重载提取和重载提取和插入运算符插入运算符13.4 13.4 应用举例应用举例13.1 13
2、.1 基本概念基本概念字节流字节流(Stream)Stream)字节流字节流:数据的字节序列数据的字节序列。分为分为字符流和二进制流字符流和二进制流字符流字符流(文本流文本流):将字节流的每个字节按将字节流的每个字节按ASCIIASCII码字符码字符解释。传输时需做转换,效率低。因解释。传输时需做转换,效率低。因ASCIIASCII码是标准的,码是标准的,故字符流可直接编辑、显示和打印,通行各类计算机故字符流可直接编辑、显示和打印,通行各类计算机 整型数值整型数值12345671234567在内存中占在内存中占4 4字节,但输出前要先字节,但输出前要先转换成数值串转换成数值串“12345671
3、234567”,才能输出。反之亦然,才能输出。反之亦然 源程序文件和文本文件都是字符流源程序文件和文本文件都是字符流二进制流:二进制流:将字节流的每个字节按二进制数解释。传将字节流的每个字节按二进制数解释。传输时不做转换,效率高。二进制数据在各类计算机中输时不做转换,效率高。二进制数据在各类计算机中的存放格式有差异,其可移植性差,无法人工阅读的存放格式有差异,其可移植性差,无法人工阅读文件文件 文件:文件:相关数据的字节序列集合相关数据的字节序列集合 程序、数据、文档常以文件形式存于外存程序、数据、文档常以文件形式存于外存 输入输入/输出设备具有字节流特征,也是文件。如键输出设备具有字节流特征
4、,也是文件。如键盘是输入文件,显示器、打印机是输出文件盘是输入文件,显示器、打印机是输出文件 不同的文件所允许的操作可能不同。如磁盘文件可不同的文件所允许的操作可能不同。如磁盘文件可将数据写入,也可将数据取出;而打印机文件只能将数据写入,也可将数据取出;而打印机文件只能将数据写入,而不能将数据取出将数据写入,而不能将数据取出 文件名:文件名:为文件取的名字,以别于其它文件为文件取的名字,以别于其它文件 程序可通过文件名来使用文件程序可通过文件名来使用文件 文件名通常使用标识符。但不同的计算机系统,对文件名通常使用标识符。但不同的计算机系统,对文件名的组成规则有所不同文件名的组成规则有所不同缓冲
5、缓冲 缓冲区:缓冲区:系统在内存中开辟的、用来临时存放输入系统在内存中开辟的、用来临时存放输入/输出数据的区域。如先将输入的数据送到缓冲区,再输出数据的区域。如先将输入的数据送到缓冲区,再从缓冲区中取出从缓冲区中取出 缓冲区的作用:缓冲区的作用:因输入因输入/输出设备的速度比输出设备的速度比CPUCPU慢得多,慢得多,若若CPUCPU直接与外设交换数据,必然占用大量直接与外设交换数据,必然占用大量CPUCPU时间,时间,降低降低CPUCPU的使用效率。使用缓冲后,的使用效率。使用缓冲后,CPUCPU只要从缓冲区只要从缓冲区中取数据或者把数据写入缓冲区,而不必等待外设的中取数据或者把数据写入缓冲
6、区,而不必等待外设的具体输入具体输入/输出操作,显著提高了输出操作,显著提高了CPUCPU的使用效率的使用效率 I I/O O流分为缓冲流和非缓冲流。流分为缓冲流和非缓冲流。缓冲流较常用缓冲流较常用 非缓冲流:一旦数据送入缓冲区,立即处理非缓冲流:一旦数据送入缓冲区,立即处理 缓冲流:仅当缓冲区满或当前送入的数据为新的一缓冲流:仅当缓冲区满或当前送入的数据为新的一行字符时,才做处理行字符时,才做处理(称为刷新称为刷新)13.2 13.2 文件文件根据对字节内容的不同解释,将根据对字节内容的不同解释,将文件分为文件分为:文本文件文本文件(ASCIIASCII码文件码文件):每个字节为字符:每个字
7、节为字符二进制文件:每个字节为二进制数据二进制文件:每个字节为二进制数据文件流类:文件流类:ifstreamifstream:输入文件流类,用于文件输入输入文件流类,用于文件输入ofstreamofstream:输出文件流类,用于文件输出输出文件流类,用于文件输出fstreamfstream:输入输入/输出文件流类,用于文件输入输出文件流类,用于文件输入/输出输出文件流对象:文件流对象:与预定义的标准流对象相似。区别:与预定义的标准流对象相似。区别:文件流对象需用户定义后方可使用文件流对象需用户定义后方可使用文件流对象可与用户指定的文件关联文件流对象可与用户指定的文件关联文件流的用法文件流的用
8、法说明一个文件流对象说明一个文件流对象。例如:。例如:ofstream ofstream outfileoutfile;fstream fstream iofileiofile;用文件流对象的成员函数用文件流对象的成员函数openopen或构造函数,打开指定或构造函数,打开指定文件文件。例如:。例如:outfileoutfile.open(myf1.txt)open(myf1.txt);ifstream ifstream infileinfile(myf2.txt)(myf2.txt);用文件流对象的提取、插入运算符或成员函数读用文件流对象的提取、插入运算符或成员函数读/写指写指定文件定文件。
9、例如:。例如:infileinfilechch;文件使用结束,关闭文件文件使用结束,关闭文件infileinfile.close().close();文件的打开文件的打开用文件流类的成员函数用文件流类的成员函数openopen打开文件打开文件:void open(const char*filename,ios_base:openmode mode);指定打开的文件名:指定打开的文件名:可含盘符和可含盘符和路径,如路径,如“d:d:t t 1.1.datdat”指定文件的打开方式:指定文件的打开方式:如表如表13.113.1所示。其中,所示。其中,输入文件流的缺省值为输入文件流的缺省值为iosi
10、os_base:in_base:in输出文件流的缺省值为输出文件流的缺省值为iosios_base:out|_base:out|iosios_base:_base:trunctrunc输入输出文件流的缺省值为输入输出文件流的缺省值为iosios_base:in|_base:in|iosios_base:out_base:out作用作用方式方式二进制方式打开文件。总与输入或输出方式组二进制方式打开文件。总与输入或输出方式组合使用合使用iosios_base:binary_base:binary清空文件。若单用,则与清空文件。若单用,则与iosios_base:out_base:out等价等价io
11、sios_base:_base:trunctrunc输出方式打开文件。若文件不存在,则产生一输出方式打开文件。若文件不存在,则产生一个新文件;若文件存在,则清空文件个新文件;若文件存在,则清空文件iosios_base:out_base:out输入方式打开文件。若文件不存在,则出错输入方式打开文件。若文件不存在,则出错iosios_base:in_base:in添加输出方式打开文件后,文件指针添加输出方式打开文件后,文件指针最初最初指向指向文件尾,但随后可改变指向文件尾,但随后可改变指向iosios_base:ate_base:ate追加输出方式打开文件后,文件指针追加输出方式打开文件后,文件
12、指针始终始终指向指向文件尾,所有输出写入文件尾。若文件不存在,文件尾,所有输出写入文件尾。若文件不存在,则产生一个新文件则产生一个新文件iosios_base:app_base:app表表13.1 13.1 文件的打开方式文件的打开方式文件打开方式说明文件打开方式说明若不矛盾,则可用位或运算符将几种打开方式组合若不矛盾,则可用位或运算符将几种打开方式组合使用使用不以二进制方式打开的文件,都是文本文件不以二进制方式打开的文件,都是文本文件文件指针文件指针从从0 0开始连续编号开始连续编号(0(0代表文件头代表文件头),以字节,以字节为单位,用于指示文件的读为单位,用于指示文件的读/写位置。文件每
13、读写位置。文件每读/写写一个字节,文件指针就后移一个字节。一个字节,文件指针就后移一个字节。文件指针的初值文件指针的初值由文件打开方式指定。若文件打开由文件打开方式指定。若文件打开方式含方式含iosios_base:app_base:app或或iosios_base:ate_base:ate,则文件指,则文件指针指向文件尾,否则指向文件头针指向文件尾,否则指向文件头文件的打开文件的打开 用文件流类的构造函数打开文件:用文件流类的构造函数打开文件:文件流类文件流类ifstreamifstream、ofstreamofstream和和fstreamfstream的构造函数所带参数与其成员函的构造函
14、数所带参数与其成员函数数openopen所带参数完全相同所带参数完全相同 在说明文件流类的对象时,通过调用各自的构造函数在说明文件流类的对象时,通过调用各自的构造函数打开文件。打开文件。例如:例如:读方式打开文件读方式打开文件ifstreamifstream f1(file1.f1(file1.datdat););写方式打开文件写方式打开文件ofstreamofstream f2(file2.txt);f2(file2.txt);读方式打开文件读方式打开文件fstreamfstream f3(file3.f3(file3.datdat,iosios_base:in_base:in););文件的
15、打开文件的打开文件打开与否的判断:文件打开与否的判断:文件打开后,应判断打开是否文件打开后,应判断打开是否成功。若不成功,则后续的文件读成功。若不成功,则后续的文件读/写操作就没有实际写操作就没有实际意义。例如:意义。例如:ifstreamifstream f1(C:f1(C:mymy file.file.datdat););if(if(!f1!f1)coutcout”和插入运算符和插入运算符“”来读写来读写文件文件 例例13.113.1 复制源文件到目标文件。复制源文件到目标文件。#include#include#include#include using namespace std;usi
16、ng namespace std;intint main(void)main(void)char char chch,f1256,f2256;,f1256,f2256;coutcoutf1;f1;coutcoutf2;f2;ifstreamifstream in(f1)in(f1);ofstreamofstream out(f2)out(f2);if(!in)if(!in)coutcout n n不能打开源文件:不能打开源文件:f1;return 1;f1;return 1;if(!out)if(!out)coutcout n n不能打开目标文件:不能打开目标文件:innoskipwsnosk
17、ipws;/;/不跳过空白符,因文件复制应包含空白符不跳过空白符,因文件复制应包含空白符while(while(ininchch)outoutinchch的返回值为的返回值为inin,做做whilewhile语句的条件。但因不语句的条件。但因不是基本类型数据,无法直接是基本类型数据,无法直接运算,除非做类型转换运算,除非做类型转换iosios类仅重载了一个类型转类仅重载了一个类型转换函数换函数:operator void*()operator void*()return fail()?0:this;return fail()?0:this;隐式类型转换:隐式类型转换:(void*)in fai
18、l()?0:thisvoid*)in fail()?0:this等价于:等价于:while(in.get(while(in.get(chch)outoutchch;问题:问题:本程序为何也能复制任意类型的文件?本程序为何也能复制任意类型的文件?例例13.213.2 设文本文件设文本文件data.txtdata.txt中有若干实数,每个实数之间用空中有若干实数,每个实数之间用空格或换行符隔开。求出文件中的这些实数的平均值。格或换行符隔开。求出文件中的这些实数的平均值。#include#include#include#include using namespace std;using namesp
19、ace std;intint main(void)main(void)float sum=0,t;float sum=0,t;intint count=0;count=0;ifstreamifstream in(data.txt);in(data.txt);if(!in)if(!in)coutcoutt)/while(int)/依次读一个实数依次读一个实数sum+=t,count+;sum+=t,count+;coutcout实数的平均值实数的平均值=sum/countsum/count,实数的个数实数的个数=countcountendlendl;in.close();in.close();return 0;return 0;设文件设文件data.txtdata.txt的内容为:的内容为:240.5 5.6 31.7 80 99.8 20 50240.5 5.6 31.7 80 99.8 20 50程序运行结果:程序运行结果:实数的平均值实数的平均值=75.3714,=75.3714,实数的个数实数的个数=7=7