1、C+程序设计第第9 9章章 输入输出流输入输出流第第9章章输入输出流输入输出流 本章学习要点本章学习要点完成程序的基本功能需要有初始数据的完成程序的基本功能需要有初始数据的输入和运行结果的输出输入和运行结果的输出.本章重点介绍本章重点介绍C+输入输入/输出流库、预定输出流库、预定义类型数据的输入和输出、格式控制、义类型数据的输入和输出、格式控制、自定义类型数据的输入和输出以及文件自定义类型数据的输入和输出以及文件的输入和输出等内容。的输入和输出等内容。v9.1 C+的输入和输出概述的输入和输出概述v9.2 C+的标准输入的标准输入/输出流输出流v9.3 输入运算符和输出运算符及其重载输入运算符
2、和输出运算符及其重载v9.4 C+格式输入和输出格式输入和输出v9.5 文件操作与文件流文件操作与文件流v9.6 学生信息管理系统中的文件操作学生信息管理系统中的文件操作 第第9章输入输出流章输入输出流9.5 文件操作与文件流文件操作与文件流9.5.1 文件的概念文件的概念v所谓所谓“文件文件”,一般指存储在外部介质上数一般指存储在外部介质上数据的集合据的集合。一批数据是以文件的形式存放在。一批数据是以文件的形式存放在外部介质上的。操作系统是以文件为单位对外部介质上的。操作系统是以文件为单位对数据进行管理的,也就是说,如果想找存储数据进行管理的,也就是说,如果想找存储在外部介质上的数据,必须先
3、按文件名找到在外部介质上的数据,必须先按文件名找到指定的文件,然后再从文件中读取数据。要指定的文件,然后再从文件中读取数据。要向外部介质上存储数据也必须先建立一个文向外部介质上存储数据也必须先建立一个文件(以文件名标识),才能向它输出数据。件(以文件名标识),才能向它输出数据。v根据文件中数据的组织形式根据文件中数据的组织形式,文件文件可分为可分为ASCII文件文件和和二进制文件二进制文件。vASCII文件文件也称文本文件,其每个字节存一也称文本文件,其每个字节存一个个ASCII代码,表示一个字符。这样的文件使代码,表示一个字符。这样的文件使用比较方便,但占用的存储空间较大。用比较方便,但占用
4、的存储空间较大。v二进制文件二进制文件,是把内存中的存储形式原样写,是把内存中的存储形式原样写到外存储器中。使用起来可以节省外存空间到外存储器中。使用起来可以节省外存空间和转换时间,但是它的一个字节不对应一个和转换时间,但是它的一个字节不对应一个字符。字符。9.5 文件操作与文件流文件操作与文件流v为了实现文件的输入和输出为了实现文件的输入和输出,首先要创建一个首先要创建一个文件流文件流,当把这个流和实际的文件相关联时,当把这个流和实际的文件相关联时,就称为就称为打开文件打开文件。完成输入和输出后要。完成输入和输出后要关闭关闭这这个个文件文件,即取消文件和流的关联即取消文件和流的关联。9.5
5、文件操作与文件流文件操作与文件流9.5.2 文件流类及其流对象文件流类及其流对象在在C+的的I/O流类库中流类库中定义了几种定义了几种文件流类文件流类,专,专门用于对磁盘文件的输入输出操作。它们是:门用于对磁盘文件的输入输出操作。它们是:ifstream类类(支持从磁盘文件的输入支持从磁盘文件的输入)ofstream类类(支持向磁盘文件的输出支持向磁盘文件的输出)fstream类类(支持对磁盘文件的输入输出支持对磁盘文件的输入输出)9.5 文件操作与文件流文件操作与文件流vC+建立了一个十分庞大的流类库来实现数据的输入/输出操作,其中的每个流类实现不同的功能,这些类通过继承组合在一起。C+I/
6、O流类的继承结构流类的继承结构C+I/O流类的继承结构流类的继承结构9.5.2 文件流类及其流对象文件流类及其流对象如果以磁盘文件为对象进行输入输出,必须先如果以磁盘文件为对象进行输入输出,必须先定义定义一个一个文件流类的对象文件流类的对象,通过文件流对象将数,通过文件流对象将数据从内存输出到磁盘文件,或者通过文件流对象据从内存输出到磁盘文件,或者通过文件流对象从磁盘文件将数据输入到内存。从磁盘文件将数据输入到内存。9.5 文件操作与文件流文件操作与文件流ofstream outfile;/建立一个输出文件流对象建立一个输出文件流对象outfileifstream infile;/建立一个输入
7、文件流对象建立一个输入文件流对象infilefstream file;/建立一个输入输出文件流对象建立一个输入输出文件流对象file9.5.2 文件流类及其流对象文件流类及其流对象由于由于cin和和cout已在已在iostream.h中事先定义,中事先定义,所以用户不需自己定义就可以使用。但在通过文所以用户不需自己定义就可以使用。但在通过文件流对象对磁盘文件进行操作时,件流对象对磁盘文件进行操作时,文件流对象没文件流对象没有事先统一定义,必须由用户自己定义有事先统一定义,必须由用户自己定义。注意注意:如果要在程序中建立文件流对象,必须:如果要在程序中建立文件流对象,必须包含头文件包含头文件fs
8、tream.h。9.5 文件操作与文件流文件操作与文件流9.5.3 文件的打开与关闭文件的打开与关闭磁盘文件的打开和关闭使用文件流类中定义的磁盘文件的打开和关闭使用文件流类中定义的成员函数成员函数open()和和close()【每个文件流类都提每个文件流类都提供有供有open()和和close()】。9.5 文件操作与文件流文件操作与文件流1文件的打开文件的打开要对磁盘文件进行读写操作,首先必须要先打要对磁盘文件进行读写操作,首先必须要先打开文件。所谓开文件。所谓打开文件打开文件就是就是将文件流对象与具体将文件流对象与具体的磁盘文件建立联系,并指定相应的使用方式的磁盘文件建立联系,并指定相应的
9、使用方式。以上工作可以通过两种不同的方法实现:以上工作可以通过两种不同的方法实现:(1)先说明一个)先说明一个fstream类的对象,再调用该类的对象,再调用该对象的成员函数对象的成员函数open()打开指定的文件。例如,打开指定的文件。例如,以输出方式打开一个文件的方法如下:以输出方式打开一个文件的方法如下:ofstream outfile;outfile.open(file1.dat);9.5 文件操作与文件流文件操作与文件流open()函数的函数原型为:函数的函数原型为:void open(const char*filename,int mode,int access=filebuf:o
10、penprot);第一个参数第一个参数filename指定要打开的文件名,使用文件名指定要打开的文件名,使用文件名时可以包括路径,如时可以包括路径,如“d:datafile1.dat”,如果默认路,如果默认路径,则默认为当前目录下的文件。径,则默认为当前目录下的文件。第二个实参第二个实参mode表表示文件的访问方式,见课本示文件的访问方式,见课本262页表页表9-4,其中有一些访,其中有一些访问方式是相互问方式是相互“兼容兼容”的,可以通过的,可以通过“|”(或运算符)(或运算符)结合起来结合起来。方式名用途ios:inios:out以输入(读)方式打开文件(适用于ifstream),如果文件
11、不存在,open函数将失败。以输出(写)方式打开文件(适用于ofstream),如果文件已存在,文件的内容将被刷新。ios:app以追加方式打开文件,如果文件已存在,保留原内容,新增加的内容添加在文件尾。如果文件不存在,将创建一个新文件。ios:ate文件打开时,文件指针定位于文件尾ios:trunc如果文件存在,文件的内容将被刷新;如果文件不存在,创建新文件。ios:binary以二进制方式打开文件,缺省时为文本文件。ios:nocreate打开已有文件,若文件不存在,则打开失败。ios:noreplace如果文件不存在,则建立新文件;若文件已经存在,则打开失败。/以读以读/写方式打开文件,
12、适用于写方式打开文件,适用于fstream流对象流对象ios:in|ios:out ios:in|ios:binary/以二进制读方式打开文件以二进制读方式打开文件ios:out|ios:binary/以二进制写方式打开文件以二进制写方式打开文件/以二进制读以二进制读/写方式打开文件,适用于写方式打开文件,适用于fstream流对象流对象ios:in|ios:out|ios:binary 如:如:file.open(file1.dat,ios:in|ios:out);open()函数的函数原型为:函数的函数原型为:void open(const char*filename,int mode,i
13、nt access=filebuf:openprot);第三个参数第三个参数access表示表示文件的共享模式文件的共享模式 filebuf:openport共享方式共享方式 filebuf:sh_none独占方式,不允许共享独占方式,不允许共享 filebuf:sh_read允许读共享允许读共享 filebuf:sh_write允许写共享允许写共享(2)在定义文件流对象时同时指定参数在定义文件流对象时同时指定参数在声明文件流类时定义了带参数的构造函数,在声明文件流类时定义了带参数的构造函数,其中包含了打开磁盘文件的功能。因此,可以其中包含了打开磁盘文件的功能。因此,可以在定义文件流对象时指定
14、参数,调用文件流类在定义文件流对象时指定参数,调用文件流类的构造函数来实现打开文件的功能。如要实现的构造函数来实现打开文件的功能。如要实现(1)中说明的以输出方式打开一个文件,方法)中说明的以输出方式打开一个文件,方法如下:如下:ofstream outfile(f1.dat,ios:out);一般多用此形式一般多用此形式,相比(,相比(1)来说比较方便。)来说比较方便。作用与作用与open()函数相同,参数含义相同。函数相同,参数含义相同。9.5 文件操作与文件流文件操作与文件流该参数可省略,它该参数可省略,它是是ofstream类对象类对象默认的访问方式默认的访问方式注意注意:如果打开操作
15、失败,:如果打开操作失败,open函数的返回函数的返回值为值为0(假),如果是用调用构造函数的方式打(假),如果是用调用构造函数的方式打开文件的,则流对象的值为开文件的,则流对象的值为0。9.5 文件操作与文件流文件操作与文件流2关闭磁盘文件关闭磁盘文件当结束一个磁盘文件的读写操作后,应关闭当结束一个磁盘文件的读写操作后,应关闭该文件,该文件,以防文件被以防文件被“误用误用”。关闭文件用。关闭文件用成员函数成员函数close()。如:。如:outfile.close();9.5 文件操作与文件流文件操作与文件流3读读/写文件写文件读文件读文件:从一个文件中读取数据,可以从一个文件中读取数据,可
16、以使用使用get、getline、read函数函数以及以及提取符提取符“”;写文件写文件:向一个文件写入数据,可以向一个文件写入数据,可以使用使用put、write函数函数以及以及插入符插入符“”9.5 文件操作与文件流文件操作与文件流9.5.4 对文本文件的操作对文本文件的操作如果文件的每一个字节中均以如果文件的每一个字节中均以ASCII代码形代码形式存放数据,即式存放数据,即一个字节存放一个字符一个字节存放一个字符,这,这个文件就是个文件就是ASCII文件文件(或称文本文件)。程(或称文本文件)。程序可以从序可以从ASCII文件中读入若干个字符,也可文件中读入若干个字符,也可以向它输出一些
17、字符。以向它输出一些字符。9.5 文件操作与文件流文件操作与文件流9.5.4 对文本文件的操作对文本文件的操作对文本文件的对文本文件的读写操作读写操作可以可以用用流插入运算符流插入运算符“”输入输出标准类型输入输出标准类型的数据,也可以用文件流的的数据,也可以用文件流的put(),get(),getline()等成员函数进行字符的输入输出。等成员函数进行字符的输入输出。9.5 文件操作与文件流文件操作与文件流【例例9-15】把文本写入指定的文件中。把文本写入指定的文件中。9.5 文件操作与文件流文件操作与文件流#include#include#include using namespace s
18、td;int main()fstream outfile(f2.dat,ios:out);if(!outfile)/如果打开失败,outfile返回0值 cerrf2.dat open error!nendl;exit(1);outfileHello world.n;outfileHello country.n;outfile.close();/关闭磁盘文件f2.dat return 0;【例例9-16】从文本文件中读出文本信息。从文本文件中读出文本信息。9.5 文件操作与文件流文件操作与文件流#include#include#include using namespace std;int m
19、ain()char s100;fstream infile(f2.dat,ios:in);if(!infile)/如果打开失败,infile返回0值 cerrf2.dat open error!ns;if(infile.fail()break;coutsendl;infile.close();/关闭磁盘文件f2.dat return 0;【例例9-16】从文本文件中读出文本信息。从文本文件中读出文本信息。9.5 文件操作与文件流文件操作与文件流#include#include#include using namespace std;int main()char s100;fstream inf
20、ile(f2.dat,ios:in);if(!infile)/如果打开失败,infile返回0值 cerrf2.dat open error!nendl;exit(1);while(!infile.eof()infile.getline(s,sizeof(s);coutsendl;infile.close();/关闭磁盘文件f2.dat return 0;9.5 文件操作与文件流文件操作与文件流v【例充例题例充例题】假设有学生的假设有学生的chinese、math、computer成绩表如下:成绩表如下:张三,张三,76,98,67;李四,;李四,89,70,60;王十,王十,91,88,77
21、;黄二,;黄二,62,81,75;刘六,刘六,90,78,67v用用fstream文件流在目录文件流在目录D:dk下建立下建立a.dat文件,文件,并将上述学生成绩写入文件中。然后以二进制并将上述学生成绩写入文件中。然后以二进制方式打开建立的文件,读出文件中的数据,计方式打开建立的文件,读出文件中的数据,计算每个学生的总成绩并将它显示在屏幕上。算每个学生的总成绩并将它显示在屏幕上。#include#include using namespace std;int main()fstream ioFile;ioFile.open(C:dka.dat,ios:out);ioFile张三张三 76 9
22、8 67endl;ioFile李四李四 89 70 60endl;ioFile王十王十 91 88 77endl;ioFile黄二黄二 62 81 75endl;ioFile刘六刘六 90 78 67endl;ioFile.close();return 0;ioFile.open(C:dka.dat,ios:in|ios:binary);char name10;int chinese,math,computer;cout姓名姓名t英语英语t数学数学t计算机计算机t总分总分name;while(!ioFile.eof()ioFilechinesemathcomputer;coutnametchi
23、nesetmathtcomputertchinese+math+computername;ioFile.close();v对于单字符的输入和输出可以使用成员函对于单字符的输入和输出可以使用成员函数数get()和和put()。下面再举一个使用。下面再举一个使用get()和和put()进行文件读写的例子。进行文件读写的例子。v【例例9-17】使用使用get()和和put()进行文本文件进行文本文件读写。读写。9.5 文件操作与文件流文件操作与文件流【例例9-17】使用使用get()和和put()进行文本文件读写。进行文本文件读写。9.5 文件操作与文件流文件操作与文件流#include#inclu
24、de#include#include using namespace std;int main()fstream infile,outfile;/定义文件流对象 char ch,str=Hello world;outfile.open(ff.dat,ios:out);if(!outfile)/如果打开失败,outfile返回0值 cerrff.dat open error!nendl;exit(1);for(int i=0;i=strlen(str);i+)outfile.put(stri);outfile.close();【例例9-17】使用使用get()和和put()进行文本文件读写。进行
25、文本文件读写。9.5 文件操作与文件流文件操作与文件流 infile.open(ff.dat,ios:in);if(!infile)/如果打开失败,infile返回0值 cerrff.dat open error!nendl;exit(1);while(infile.get(ch)coutch;coutendl;infile.close();/关闭磁盘文件ff.dat return 0;9.5.5 对二进制文件的操作对二进制文件的操作二进制文件二进制文件中的信息不是字符数据,而是字节中的信息不是字符数据,而是字节中的二进制形式的信息,因此又称为它字节文件。中的二进制形式的信息,因此又称为它字节
26、文件。对二进制文件的操作同样是使用时要先打开文件,对二进制文件的操作同样是使用时要先打开文件,用完后要关闭文件。用完后要关闭文件。在打开时要用在打开时要用ios:binary指指定为以二进制形式传送和存储定为以二进制形式传送和存储。二进制文件除了。二进制文件除了可以作为输入文件或输出文件外,还可以是既能可以作为输入文件或输出文件外,还可以是既能输入又能输出的文件。这是和输入又能输出的文件。这是和ASCII文件不同的文件不同的地方。地方。9.5 文件操作与文件流文件操作与文件流9.5.5 对二进制文件的操作对二进制文件的操作9.5 文件操作与文件流文件操作与文件流 用get和put按字节方式读写
27、文件数 read和write 按数据块的方式读写文件数据【补充例题补充例题】用二进制方式建立一个磁盘文件,将ASCII 编码为090之间的字符写入到文件D:dkb.dat中,然后用二进制文件方式读出并在屏幕上显示b.dat的内容。#include#include using namespace std;int main()char ch;ofstream out(“D:dkb.dat,ios:out|ios:binary);for(int i=0;i90;i+)if(!(i%30)out.put(n);out.put(char(i);out.put();out.close();ifstream
28、 in(“D:dkb.dat,ios:in|ios:binary);while(in.get(ch)coutch;in.close();return 0;【例【例9-18】将将4个学生的信息写到个学生的信息写到student.dat文件文件中,并读出检测。中,并读出检测。9.5 文件操作与文件流文件操作与文件流#include#include#include using namespace std;struct person char name20;int age;char sex;【例例9-15】把文本写入指定的文件中。把文本写入指定的文件中。9.5 文件操作与文件流文件操作与文件流int
29、main()person stud4=Li,18,f,Zhang,19,m,Wang,17,f,Bao,18,m;ofstream outfile(student.dat,ios:binary);if(!outfile)cerropen error!endl;abort();for(int i=0;i4;i+)outfile.write(char*)&studi,sizeof(studi);outfile.close();【例例9-15】把文本写入指定的文件中。把文本写入指定的文件中。9.5 文件操作与文件流文件操作与文件流ifstream infile(student.dat,ios:bin
30、ary);if(!infile)cerropen error!endl;abort();for(i=0;i4;i+)infile.read(char*)&studi,sizeof(studi);infile.close();for(i=0;i4;i+)cout name:studi.name t age:studi.age t sex:studi.sexendl;return 0;v9.5.6 随机访问二进制文件随机访问二进制文件v前面所举的例子都是按顺序访问方式进行的。但是前面所举的例子都是按顺序访问方式进行的。但是对于二进制文件,我们还可以对它进行随机访问。对于二进制文件,我们还可以对它进
31、行随机访问。在对一个文件进行读写操作时,系统会为该文件设在对一个文件进行读写操作时,系统会为该文件设置一个读写指针,用于指示当前读写的位置。置一个读写指针,用于指示当前读写的位置。iostream类类对读指针进行操作对读指针进行操作提供了三个成员函数:提供了三个成员函数:vistream&istream:seekg()vistream&istream:seekg(,)vistream&istream:tellg()v其中,其中,、都是都是long型量,并以型量,并以字节为单位。而字节为单位。而具有三个含义:具有三个含义:cur=1表表示相对于当前读指针所指定的位置;示相对于当前读指针所指定的位
32、置;beg=0表示相对表示相对于流的开始位置;于流的开始位置;end=2表示相对于流的结尾处。表示相对于流的结尾处。9.5 文件操作与文件流文件操作与文件流例如,设例如,设input是一个是一个istream类型的流,则类型的流,则input.seekg(-100,ios:cur);表示使读指针以当前位置为基准向前移动表示使读指针以当前位置为基准向前移动100个字节。个字节。iostream类类对写指针进行操作对写指针进行操作也提供了三个成员函数:也提供了三个成员函数:ostream&ostream:seekp()ostream&ostream:seekp(,)ostream&ostream:
33、tellp()这三个成员函数的含义与操作同读指针的三个成员函数这三个成员函数的含义与操作同读指针的三个成员函数的含义相同,只是在这里表示操作写指针。的含义相同,只是在这里表示操作写指针。【例例9-19】随机访问二进制文件举例。随机访问二进制文件举例。9.5 文件操作与文件流文件操作与文件流【例例9-19】随机访问二进制文件举例。随机访问二进制文件举例。9.5 文件操作与文件流文件操作与文件流#include#include#include using namespace std;struct person char name20;int age;char sex;【例例9-15】把文本写入指定
34、的文件中。把文本写入指定的文件中。9.5 文件操作与文件流文件操作与文件流int main()/用来存放从磁盘文件读入的数据Person stud4=Li,18,f,Zhang,19,m,Wang,17,f,Bao,18,m;fstream iofile(student.dat,ios:in|ios:out|ios:binary);if(!iofile)cerropen error!endl;abort();for(int i=0;i4;i+)/向磁盘文件输出4个学生的数据 iofile.write(char*)&studi,sizeof(studi);【例例9-15】把文本写入指定的文件中。
35、把文本写入指定的文件中。9.5 文件操作与文件流文件操作与文件流person stud14;/用来存放从磁盘文件读入的数据for(i=0;i4;i=i+2)/定位于第0,2学生数据开头iofile.seekg(i*sizeof(studi),ios:beg);/先后读入第0,2个学生(序号为0,2)的数据,存放在stud10和stud12中iofile.read(char*)&stud1i,sizeof(stud1i);/输出stud10,stud2各数据成员的值coutstud1i.name,stud1i.age,;coutstud1i.sexendl;9.6 学生信息管理系统中的文件学生信息管理系统中的文件操作操作在学生信息管理系统中,关于文件的操作主在学生信息管理系统中,关于文件的操作主要是写入学生信息和读出学生信息,因为在系要是写入学生信息和读出学生信息,因为在系统中没有用到数据库,所以一切信息都是写入统中没有用到数据库,所以一切信息都是写入到文件中的。系统中的学生类到文件中的。系统中的学生类Student和函授生和函授生类类Correspodence都提供了实现读写学生信息都提供了实现读写学生信息的成员函数的成员函数ReadFromFile()和和WriteToFile()。这些成员函数的实现代码参见第这些成员函数的实现代码参见第4.8节。节。