1、C+具有一个功能强大的I/O类继承体系结构用于处理数据的输入/输出问题该体系结构不仅提供了对系统内置数据类型的输入/输出操作,而且允许程序员通过重载扩展其功能以实现自定义数据类型的输入和输出操作。本章主要介绍C+流的基本结构,数据的输入输出及其格式化问题,同时还介绍了C+文件的编程技术。,第7章 文件与流,1、流的概念所谓流,是指数据的有向流动,即数据从一个设备流向另一个设备 。流实际上是一种对象,它在使用前被建立,使用后被删除。数据的输入/输出操作就是从流中提取数据或者向流中添加数据。通常把从流中提取数据的操作称为析取,即读操作;向流中添加数据的操作称为插入操作,即写操作。,7.1 C+ I
2、/O流及流类库,2、C+ I/O流类的继承结构C+建立了一个十分庞大的流类库来实现数据的输入/输出操作,其中的每个流类实现不同的功能,这些类通过继承组合在一起。,7.1 C+ I/O流及流类库,3、C+主要的流类简介streambuf主要作为其他类的支持,定义了对缓冲区的通用操作,如设置缓冲区,从缓冲区中读取数据,或向缓冲区写入数据等操作filebuf类使用文件来保存缓冲区中的字符序列。它定义了文件读、写、打开、关闭等常用操作。 ios是所有流类的基类,提供对流状态进行设置的主要功能。如文件数据的格式码设置与取消,关链文件缓冲区借以实现数据读写等,7.1 C+ I/O流及流类库,istream
3、是输入流类,实现数据输入的功能;ostream是输出流类,实现数据输出的功能;iostream是istream和ostream的派生类,它继承了istream类和ostream类的行为,支持数据输入、输出的双向操作,在程序中常通过它来实现数据的输入与输出功能。fstreambase从ios派生,提供了文件操作的许多功能,作为其他文件操作类的公共基类。ifstream类用来实现文件读取操作,ofstream类用来实现文件写入操作。fstream继承了fstreambase和iostream类的功能,实现了文件读/写的双向操作。,7.1 C+ I/O流及流类库,4、C+预定义的输入/输出流对象为了
4、便于程序数据的输入/输出,C+预定义了几个标准输入/输出流对象。在程序中可以直接引用它们来输入/输出数据。如下表所示,7.1 C+ I/O流及流类库,1、用Cin输入数据的问题用cin输入字符串数据时,如果字符串中含有空白就不能完整输入。因为遇到空白字符时,cin就认为字符串结束了。【例9-1】 用cin输入字符串的问题。/Eg9-1.cpp#includeusing namespace std;void main() char a50; couta; coutaendl;,7.2 使用I/O成员函数,若a的内容是:this is a string! 就难以输入啦!这样的数据应用输入流类的成员
5、函数输入,1、istream类定义了许多用于从流中提取数据和操作文件的成员函数 ,如下所示class istream : virtual public ios public:istream,7.2.1 istream流中的常用成员函数,istream 或istream.h头文件中找到此class的声明!,2、几个常用的输入流成员函数(1)int get( )(2)istream,7.2.1 istream流中的常用成员函数,【例7-2】 用函数get和getline读取数据。#include using namespace std;void main()char c,char a50,char
6、 s1100;coutuse get() input char: ;while(c=cin.get()!=n)/L1coutc;coutendl;coutuse get(a,10) input char: ;cin.get(a,10); /L2coutaendl;cin.ignore(1);/L3coutuse getline(s1,10) input char: ;cin.getline(s1,10);/L4couts1endl;,下面是程序执行时的一组输入数据和输出结果:use get() input char: abcd abcduse get(a,10) input char: 123
7、45678 12345678use getline(s1,10) input char: this is a str this is a此输入数据将建立如图所示的输入流,分析例7-2的程序执行情况,1、ostream类提供了许多用于数据输出的成员函数,并通过流的输出运算符重载,实现了对内置数据类型的输出功能。在ostream类中的声明原型如下:class _CRTIMP ostream : virtual public ios public: ostream,7.2.2 ostream流中的常用成员函数,2、几个常用输出流类的成员函数ostreamflush,7.2.2 ostream流中的常
8、用成员函数,【例7-3】 用get读取数据,用put及write输出数据的例子。/Eg7-3.cpp#includeusing namespace std;void main()char c;char a50=this is a string.;coutuse get() input char: ;while(c=cin.get()!=n) /L1 用get读取字符,遇回车键结束cout.put(c); /L2 将c中的字符输出cout.put(n);/L3 输出一个回车换行符cout.put(t).put(h).put(i).put(s).put(n); /L4 输出thiscout.wri
9、te(a,sizeof(a)-1).put(n);/L5 write一次输出多个字符coutlookt here! endl;,ios是C+所有流类的基类,它包含了C+流的主要特性 。1ios中的格式化标志ios:skipws跳过输入流中的空白字符ios:left输出数据按左对齐,如12 ios:right输出数据按右对齐,如 12ios:dec按十进制数据输出ios:oct按八进制数据输出ios:hex按十六进制数据输出ios:showbase在输出数据前面显示基数(八进制是0,十六进制是0x)ios:showpoint浮点数输出带小数点ios:uppercase 用大写字母输出十六进制数(
10、即ABCDEF,默认是小写)ios:showpos在正数前加“+”ios:scientific用科学计数法输出浮点数,如2.122E2ios:fixed用定点数形式输出浮点数,如212.2ios:unitbuf完成后立即刷新缓冲区,7.2.4 ios类提供的格式控制,2ios中的格式化成员函数setf(flags)设置指定的格式化标志flags,unsetf(flags)取消指定的格式化标志flags,setf(flags,filed)先清除、然后设置标志flags可以是上面在1中列举的格式化标志符,7.2.4 ios类提供的格式控制,3设置域宽、精度、填充字符的成员函数ch=fill()返回
11、填充字符(默认为空格),ch是一个字符变量fill(ch)设置填充字符,ch是要设置为填充的字符p=precision()获取当前浮点数的精度,p是一个整型变量precision(p)设置精度,p是一个整数,代表要设置的数字位数w=width()获取当前字段宽度(字符个数),w是整型变量width(w)设置当前字段宽度,w是代表设置输出宽度的整数,7.2.4 ios类提供的格式控制,【例7-4】 用ios成员函数及格式化标志设置输出数据的格式。/Eg7-4.cpp#includeusing namespace std;void main() char c30=this is string; d
12、ouble d=-1234.8976; cout.width(30); cout.fill(*); cout.setf(ios:left); coutc-L1endl; cout.width(30); cout.setf(ios:right); coutc-L2endl;,cout.setf(ios:dec|ios:showbase|ios:showpoint); cout.width(30); coutd-L3n; cout.setf(ios:showpoint); cout.precision(10); cout.width(30); coutd-L4n; cout.width(30);
13、cout.setf(ios:oct,ios:basefield); cout100-L5n; ,this is string*-L1*this is string-L2*-1234.90-L3*-1234.897600-L4*0144-L5,例9-4 程序运行结果如下,1、C+流类库中的每个流对象都维护着一个格式状态,它控制着数据格式化操作的细节。如输出数据的基数(默认为十进制数据)、对齐方式、精度等。2、C+还提供了一组可以对数据进行格式化的预定义操纵符(也称操纵算子),7.2.5 利用操纵符格式化数据,3、C+流类中的操纵符showbase(noshowbase)显示(不显示)数值的基数前
14、缀showpoint(noshowpoint)显示小数点(存在小数部分时才显示小数点)showpos(noshowpos)在非负数中显示(不显示)+skipws(noskips)输入数据时,跳过(不跳过)空白字符uppercase(nouppercase)十六进制显示为0X(0x),科学计数法显示E(e)dec /oct / hex十进制/八进制/十六进制left/right设置数据输出对齐方式为:左/右 对齐fixed以小数形式显示浮点数scientitific用科学计数法显示浮点数flush刷新输出缓冲区ends插入空白字符,然后刷新ostream缓冲区endl插入换行字符,然后刷新ost
15、ream缓冲区ws跳过开始的空白,7.2.5 利用操纵符格式化数据,3、C+流类中的操纵符showbase(noshowbase)显示(不显示)数值的基数前缀showpoint(noshowpoint)显示小数点(存在小数部分时才显示小数点)showpos(noshowpos)在非负数中显示(不显示)+skipws(noskips)输入数据时,跳过(不跳过)空白字符uppercase(nouppercase)十六进制显示为0X(0x),科学计数法显示E(e)dec /oct / hex十进制/八进制/十六进制left/right设置数据输出对齐方式为:左/右 对齐fixed以小数形式显示浮点数
16、scientitific用科学计数法显示浮点数flush刷新输出缓冲区ends插入空白字符,然后刷新ostream缓冲区endl插入换行字符,然后刷新ostream缓冲区ws跳过开始的空白,7.2.5 利用操纵符格式化数据,4、头文件或中的操纵符函数setfill(ch)设置ch为填充字符setprecision(n)设置精度为n位有效数字setw(w)设置数据的输出宽度为w个字符setbase(b)基数设置为b(b=8,10,16)进制,7.2.5 利用操纵符格式化数据,【例7-5】 修改例9-4,用操纵符格式化输出数据,实现同样的功能。/Eg7-5.cpp#include#includeu
17、sing namespace std;void main() char c30=this is string; double d=-1234.8976; coutsetw(30)leftsetfill(*)c-L1endl; coutsetw(30)rightsetfill(*)c-L2endl; coutdecshowbaseshowpointsetw(30)d-L3n; coutsetw(30)showpointsetprecision(10)d-L4n; coutsetw(30)setbase(8)100-L5n;,1、文件的概念文件是存储在存储介质上(如磁盘、磁带、光盘)的数据集合。2
18、、文件的类型文本文件文本文件在磁盘上存放相关字符的ASCII码,所以又称为ASCII文件。二进制文件二进制文件在磁盘上存储相关数据的二进制编码,它是把内存中的数据,按其在内存中的存储形式原样写到磁盘上而形成的文件。,7.3 文件操作,1、流与文件C+将文件看成是一个个字符在磁盘上的有序集合,用流来实现文件的读写操作 。2、与文件相关的流ifstreamofstreamfstream,7.3.1 文件与流,3、用流操作文件的过程,须经过以下4个步骤(1)建立文件流ifstream iFile; ofstream oFile; fstream ioFile; (2)打开文件 void open(c
19、onst char *filename,int mode,int access);(3)访问文件(4)关闭文件iFile.close();oFile.close();,7.3.1 文件与流,打开文件的方式,7.3.1 文件与流,文件访问模式filebuf:openport共享方式filebuf:sh_none独占方式,不允许共享filebuf:sh_read允许读共享filebuf:sh_write允许写共享,7.3.1 文件与流,【例7-6】 假设有学生的chinese、math、computer成绩表如下:张三,76,98,67;李四,89,70,60;王十,91,88,77;黄二,62,
20、81,75;刘六,90,78,67用fstream文件流在目录C:dk下建立a.dat文件,并将上述学生成绩写入文件中。然后以二进制方式打开建立的文件,读出文件中的数据,计算每个学生的总成绩并将它显示在屏幕上。,7.3.1 文件与流,/Eg7-6.cpp#include #include using namespace std;void main() fstream ioFile; ioFile.open(C:dka.dat,ios:out); ioFile张三 76 98 67endl;/L3 ioFile李四 89 70 60endl; ioFile王十 91 88 77endl; ioF
21、ile黄二 62 81 75endl; ioFile刘六 90 78 67name; while(!ioFile.eof() ioFilechinesemathcomputer;coutname; ioFile.close();,1、二进制文件与文本文件的区别在读文件时,它们判定文件结束标志的方法存在区别。在读文本文件的过程中,当get之类的成员函数遇到文件结束符时,它返回常量EOF作为文件结束标志,但二进制文件不能用EOF作为文件结束的判定值。因为EOF的值是1,若文件中某个字节的值为1,就会被误认为是文件结束符。C+提供了一个成员函数eof来解决这个问题,它的用法如下:int xx:eof
22、()其中,xx代表输入流对象,到达文件末尾时,返回一个非0值,否则返回0。,7.3.2 二进制文件,2、二进制文件操作方法用get和put按字节方式读写文件数read和write按数据块的方式读写文件数据【例9-7】 用二进制方式建立一个磁盘文件,将ASCII 编码为090之间的字符写入到文件C:dka.dat中,然后用二进制文件方式读出并在屏幕上显示a.dat的内容。,7.3.2 二进制文件,/Eg7-7.cpp#include #include using namespace std;void main() char ch; ofstream out(C:dka.dat,ios:out|i
23、os:binary);/L1 for(int i=0;i90;i+) if(!(i % 30) out.put(n);out.put(char(i);out.put( ); out.close(); ifstream in(C:dka.dat,ios:in|ios:binary);/L6 while(in.get(ch)coutch;in.close();,【例7-8】 设计一个person类,从键盘输入每个人的姓名、身份证号、年龄、地址等数据,并将每个人的信息保存在目录C:dk下的二进制文件person.dat中,然后将文件中的个人信息读出来,保存在vector类型的向量中并显示出来。,7.
24、3.2 二进制文件,/Eg7-8.cpp#include #include #include #include using namespace std;class Personprivate: char name20; char id18; int age; char addr20;public: Person() Person(char* n,char* PerId,int Age, char* Address) strcpy(name,n); strcpy(id,PerId); strcpy(addr,Address); age=Age; void display() coutnameti
25、dtagetaddrName; coutID; coutAge; coutAddr; Person s1(Name,ID,Age,Addr); out.write(char*),out.close(); ifstream in(C:dkperson.dat,ios:in|ios:binary);/L9Person s1;in.read(char*),1、顺序文件与随机文件顺序访问是指按照从前到后的顺序依次对文件进行读写操作,有些存储设备只支持顺序访问,如磁带。 随机访问也称为直接访问,可以按任意次序对文件进行读写操作 2、随机文件访问方式对于随机文件,C+流类提供了一个操作它的的文件指针,该指
26、针可在文件中移动,将它指向要读写的字节位置,然后从该位置读取或写入指定字节数的数据块,这样就实现了文件数据的随机访问。,7.3.3 随机文件,3、定位输入文件读指针的成员函数istream代表当前get 流指针的位置(用tellg) ,而且不对tellg 或tellp 的返回值进行修改。,7.3.3 随机文件,4、定位输出文件写指针的成员函数ostream put 流指针的位置(用tellp).,7.3.3 随机文件,【例7-9】 某雇员类Employee有编号、姓名、年龄、工资等数据成员。设计一个随机文件保存各雇员的各项数据。/Eg9-7.cpp#include #include #incl
27、ude using namespace std;class Employeeprivate: int number ,age; char name20; double sal;public: Employee() Employee(int num,char* Name,int Age, double Salary) number=num; strcpy(name,Name); age=Age; sal=Salary; void display() coutnumbertnametagetsalendl; ;,void main() ofstream out(Employee.dat,ios:o
28、ut|ios:binary);/定义随机输出文件 Employee e1(1,张三,23,2320); Employee e2(2,李四,32,3210); Employee e3(3,王五,34,2220); Employee e4(4,刘六,27,1220); out.write(char*)/关闭文件,/以二进制方式建立输入文件 ifstream in(Employee.dat,ios:in|ios:binary); Employee s1; /s1用于保存从文件中读出的数据 coutn-从文件中读出第3个人的数据-nn; in.seekg(2*(sizeof(s1),ios:beg) /文件指针定位到第3个数据块 in.read(char*)/读当前文件指针处的数据 ,