资源描述
1第第1010章章 流类库与输入输出流类库与输入输出10.1 10.1 流、文件以及流、文件以及C+C+的基本流类和文件流类系统的基本流类和文件流类系统* *10.2 10.2 插入与提取运算符的重载插入与提取运算符的重载10.3 10.3 对输入输出格式进行控制对输入输出格式进行控制10.4 10.4 使用预定义的插入与提取运算符对文件流进行读写操作使用预定义的插入与提取运算符对文件流进行读写操作10.5 10.5 使用类成员函数对文件流进行操作使用类成员函数对文件流进行操作10.6 10.6 texttext文件与文件与binarybinary文件文件10.7 10.7 对数据文件进行随机访问对数据文件进行随机访问210.1 10.1 流、文件以及流、文件以及C+C+的基本流类和文件流类系统的基本流类和文件流类系统- - 参看书参看书p232-234, 10.2p232-234, 10.2与与10.310.3节节 C+ C+语言中的输入输出操作语言中的输入输出操作( (功能功能) )是由它所预是由它所预定义的诸定义的诸I/OI/O流类的一个类库所提供的。流类的一个类库所提供的。 1. 1. 流流( (Stream)Stream) 流流( (stream)stream)是一个逻辑概念是一个逻辑概念,它是,它是C+C+语言对语言对所有外部设备的逻辑抽象,它所有外部设备的逻辑抽象,它代表的是某种流类类代表的是某种流类类型的一个对象型的一个对象。C+C+的的IOIO系统将每个外部设备都转系统将每个外部设备都转换成一个称为流的逻辑设备,由流来完成对不同设换成一个称为流的逻辑设备,由流来完成对不同设备的具体操作。备的具体操作。3 2. 2. 文件文件( (File)File) 文件文件( (File)File)是一个物理概念是一个物理概念,代表存储着信息集合的某,代表存储着信息集合的某个个外部介质外部介质,它是,它是C+C+语言语言对具体设备的抽象对具体设备的抽象。如,磁盘文。如,磁盘文件,显示器,键盘。件,显示器,键盘。 所有流所有流( (类对象类对象) )的行为都是相同的,而不同的文件则可的行为都是相同的,而不同的文件则可能具有不同的行为。如,磁盘文件可进行写也可进行读操作;能具有不同的行为。如,磁盘文件可进行写也可进行读操作;显示器文件则只可进行写操作;而键盘文件只可进行读操作。显示器文件则只可进行写操作;而键盘文件只可进行读操作。 当程序与一个文件交换信息时,必须通过当程序与一个文件交换信息时,必须通过“打开文件打开文件”的操作将一个文件与一个流的操作将一个文件与一个流( (类对象类对象) )联系起来。一旦建立了联系起来。一旦建立了这种联系,以后对该流这种联系,以后对该流( (类对象类对象) )的访问就是对该文件的访问,的访问就是对该文件的访问,也就是对一个具体设备的访问。可通过也就是对一个具体设备的访问。可通过“关闭文件关闭文件”的操作的操作将一个文件与流将一个文件与流( (类对象类对象) )的联系断开。的联系断开。4 3. 3. C+C+的基本流类系统的基本流类系统 在头文件在头文件 “ “iostreamiostream.h” .h” 中说明中说明( (预定义预定义) )了一批了一批基基本流类本流类: : iosios - - 基本流类的基类基本流类的基类; ; istreamistream - - 由由iosios派生,支持输入派生,支持输入( (提取提取“”)“”)操操作;作; ostreamostream - - 由由iosios派生,支持输出派生,支持输出( (插入插入“”)“”)操操作;作; iostreamiostream - - 由由istreamistream与与ostreamostream共同派生,支持输共同派生,支持输入和输出双向操作。入和输出双向操作。 5 C+ C+预定义的流预定义的流有:有: extern extern istream istream cincin; - ; - 对象对象cincin对应于对应于键盘键盘文件文件 extern extern ostream ostream coutcout; - ; - 对象对象coutcout对应于对应于显示器显示器文件文件 extern extern ostream ostream cerrcerr; - ; - 对象对象cerrcerr对应于对应于显示器显示器文件文件 extern extern ostreamostream clogclog; - ; - 对象对象clogclog对应于对应于显示器显示器文件文件 程序中可直接对上述程序中可直接对上述4 4个预定义流类对象进行读写,而不个预定义流类对象进行读写,而不必先进行必先进行“打开文件打开文件”的操作,使用完后也不需要进行的操作,使用完后也不需要进行“关关闭文件闭文件”的操作(因为这些流类对象与文件之间的联系是预的操作(因为这些流类对象与文件之间的联系是预定义好的,可认为系统已为每一程序都隐含进行了对它们的定义好的,可认为系统已为每一程序都隐含进行了对它们的打开与关闭操作)。打开与关闭操作)。 6 4. C+ 4. C+的文件流类系统的文件流类系统 在头文件在头文件“fstreamfstream.h”.h”中说明中说明( (预定义预定义) )了一批了一批文件流文件流类类,专用于,专用于磁盘文件磁盘文件: : ifstreamifstream - - 由由istreamistream派生,支持从磁盘文件中输入派生,支持从磁盘文件中输入( (读入读入) )数据;数据; ofstreamofstream - - 由由ostreamostream派生,支持往磁盘文件中输出派生,支持往磁盘文件中输出( (写出写出) )数据;数据; fstreamfstream - - 由由iostreamiostream派生,支持对磁盘文件进行派生,支持对磁盘文件进行输入和输出数据的双向操作。输入和输出数据的双向操作。 C+C+中没有预定义的文件流中没有预定义的文件流( (类对象类对象) ),程序中用到的所,程序中用到的所有文件流类对象都要进行自定义。有文件流类对象都要进行自定义。7* *10.2 10.2 插入与提取运算符的重载插入与提取运算符的重载 - - 参看书参看书p231, 10.1p231, 10.1节后半节后半对自定义类对自定义类complexcomplex重载输入输出运算符重载输入输出运算符“”“”“”:#includeclass complex double r; double i;public:complex(double r0=0, double i0=0) r=r0; i=i0; complex operator +(complex c2); complex operator *(complex c2); friend istream& operator (istream& in, complex& com); friend ostream& operator ”operator”用于完成从用于完成从istreamistream类的流类对象类的流类对象inin上(如对上(如对应实参可为应实参可为cincin,即指定从键盘上)输入一个复数的有关数据放入即指定从键盘上)输入一个复数的有关数据放入complexcomplex型引用对象型引用对象comcom中;而中;而“operator”operator”则用于实现往则用于实现往ostreamostream类的流类对象类的流类对象outout上(如对应实参可为上(如对应实参可为coutcout,即指定往屏幕上)输出即指定往屏幕上)输出complexcomplex类对象类对象comcom的的有关数据。有关数据。 3.3. 本程序重载的输入输出运算符的返回类型均为引用,为的是可使用本程序重载的输入输出运算符的返回类型均为引用,为的是可使用返回结果继续作左值,也即使返回结果能起到一个独立对象(变量)的作返回结果继续作左值,也即使返回结果能起到一个独立对象(变量)的作用,从而可使用像用,从而可使用像“coutcoutc1c2;”c1c1c2;”c1c2;”这样的调用语这样的调用语句。另外,句。另外,“operator ”operator ”的第二形参的第二形参comcom也必须被说明成引用也必须被说明成引用“complex& com”complex& com”,目的则是要将输入数据直接赋值给对应实参变量(所目的则是要将输入数据直接赋值给对应实参变量(所拥有的存储空间中)。拥有的存储空间中)。9 complex complex:operator +(complex c2) complex c;c.r=r+c2.r;c.i=i+c2.i;return c; complex complex:operator * (complex c2) complex temp;temp.r=(r*c2.r)-(i*c2.i);temp.i=(r*c2.i)+(i*c2.r);return temp;10istream& operator (istream& in, complex& com) incom.rcom.i;return in; /不可缺少,因为函数返回类型为不可缺少,因为函数返回类型为“istream&” ostream& operator (ostream& out, complex com) out(com.r, com.i)endl;return out; /不可缺少,因为函数返回类型为不可缺少,因为函数返回类型为“ostream&”void main() complex c1(1,1), c2(2,3), c3, res;coutc1=c1c2=c2;res = c1+c2;coutc1+c2=res;coutc1*c2=c1*c2;11 coutc3; coutc3+c3=c3+c3; /* 注意输入输出语句中出现的注意输入输出语句中出现的类对象类对象cout以及以及cin正是正是输输入输出重载函数中入输出重载函数中引用型形参引用型形参out以及以及in的对应实参的对应实参。即是说,。即是说,若使用若使用“coutc1;”它将等同于它将等同于“operatorc3;”则等同于使用则等同于使用“operator(cin, c3);”。 */ 程序执行后,屏幕显示结果为:程序执行后,屏幕显示结果为: c1=(1, 1)c2=(2, 3)c1+c2=(3, 4)c1*c2=(-1, 5)Input c3:3 -5c3+c3=(6, -10)1210.3 10.3 对输入输出格式进行控制对输入输出格式进行控制10.3.1 10.3.1 格式控制函数及格式控制符格式控制函数及格式控制符 10.3.2 10.3.2 输入输出格式控制示例输入输出格式控制示例 1310.3.1 10.3.1 格式控制函数及格式控制符格式控制函数及格式控制符 - - 参看书参看书p234, 10.4p234, 10.4节节 1. 1. iosios类中常用的公有格式控制成员函数类中常用的公有格式控制成员函数 在在iosios类中定义了一批公有的类中定义了一批公有的格式控制标志位格式控制标志位以及一些以及一些成员函数,通常先用某些成员函数来设置标志位,然后再使成员函数,通常先用某些成员函数来设置标志位,然后再使用另一些成员函数来进行格式输出。另外,用另一些成员函数来进行格式输出。另外,iosios类中还设置了类中还设置了一个一个longlong型的数据成员用来记录当前被设置的格式状态,该型的数据成员用来记录当前被设置的格式状态,该数据成员被称为数据成员被称为格式控制标志字格式控制标志字( (或标志状态字或标志状态字) )。标志字是。标志字是由格式控制标志位来由格式控制标志位来“合成合成”的。的。 注意,注意,iosios类作为诸多类作为诸多I/OI/O流类的基类,其公有成员函数流类的基类,其公有成员函数当然可被各派生类的对象所直接调用。当然可被各派生类的对象所直接调用。14 (1) (1) iosios:flags:flags a.a. 格式一格式一: : long flags( long long flags( long lFlagslFlags ); ); 通过参数通过参数lFlagslFlags来重新设置来重新设置标志字标志字。 表示各表示各标志位标志位的枚举常量有的枚举常量有( (参看参看p235)p235):iosios:skipwsskipwsiosios:left :left iosios:right :right .iosios:stdiostdio 每一枚举常量值都代表着格式控制标志字中的某一个二每一枚举常量值都代表着格式控制标志字中的某一个二进制位进制位( (bit)bit),当设置了某个标志位属性时,该位将取值当设置了某个标志位属性时,该位将取值“1”“1”,否则该位取值,否则该位取值“0”“0”。 15 另外注意,通过另外注意,通过使用位运算符使用位运算符“|”“|”可将多个格式控制可将多个格式控制标志位属性进行标志位属性进行“合成合成”。但从使用角度看,。但从使用角度看,所设置的标所设置的标志位属性不能产生互斥志位属性不能产生互斥。例如,格式控制标志字中设立了。例如,格式控制标志字中设立了三个平行的标志位三个平行的标志位( (iosios:decdec、iosios:octoct和和iosios:hex):hex)用于用于表示数制,程序员应保障任何时刻只设置其中的某一个标表示数制,程序员应保障任何时刻只设置其中的某一个标志位。还有表示对齐标志位的志位。还有表示对齐标志位的iosios:left:left、iosios:right:right和和i o si o s : : i n t e r n a l: : i n t e r n a l , 以 及 表 示 实 数 格 式 标 志 位 的以 及 表 示 实 数 格 式 标 志 位 的iosios:scientific:scientific和和iosios:fixed:fixed,这些互斥属性也不能同时这些互斥属性也不能同时设置。设置。 b.b. 格式二格式二: : long flags(); long flags(); 返回当前的标志字。返回当前的标志字。 16 (2) (2) iosios:setfsetf a.a. 格式一格式一: : long long setfsetf( long ( long lFlagslFlags ); ); 通过参数通过参数lFlagslFlags来设置指定的格式控制标志位。来设置指定的格式控制标志位。 注意,与注意,与flagsflags函数的函数的“替换替换”方式不同,此处为方式不同,此处为“添加添加”方式,即是说,它并不更改其它方式,即是说,它并不更改其它lFlagslFlags不涉及到的那些标不涉及到的那些标志位的当前值。志位的当前值。 b.b. 格式二格式二: : long long setfsetf( long ( long lFlagslFlags, long , long lMasklMask ); ); 设置指定的格式控制标志位的值(首先将第二参数设置指定的格式控制标志位的值(首先将第二参数lMasklMask所指定的那些位清零,而后用第一参数所指定的那些位清零,而后用第一参数lFlagslFlags所给定的值来所给定的值来重置这些标志位)。重置这些标志位)。 17 例如,为保障所设置的数制标志位不产生互斥,当要设例如,为保障所设置的数制标志位不产生互斥,当要设置置16进制时使用:进制时使用: setf(ios:hex, ios:basefield); 其中的其中的ios:basefield为一个在为一个在ios类中定义的公有静态常类中定义的公有静态常量,它的取值为量,它的取值为ios:dec|ios:oct|ios:hex。 同理,当要设置对齐标志位为同理,当要设置对齐标志位为ios:right以及实数格式标以及实数格式标志位为志位为ios:fixed,要使用:要使用: setf(ios:right, ios:adjustfield); setf(ios:fixed, ios:floatfield); 其中用到了公有静态常量其中用到了公有静态常量ios:adjustfield和和ios:floatfield。 ios:adjustfield的取值为的取值为ios:left|ios:right|ios:internal,而而ios:floatfield的取值为的取值为ios:scientific|ios:fixed。 18 (3) (3) iosios:unsetfunsetf long long unsetfunsetf( long ( long lFlagslFlags ); ); 通过参数通过参数lFlagslFlags来清除指定的格式控制标志位。来清除指定的格式控制标志位。 (4) (4) iosios:fill:fill char fill( char char fill( char cFillcFill ); ); 将将“填充字符填充字符”设置为设置为cFillcFill, , 并返回原并返回原“填充字填充字符符”。 19(5) (5) iosios:precision:precision intint precision( precision( int npint np ); ); 设置浮点数精度为设置浮点数精度为npnp并返回原精度。当格式为并返回原精度。当格式为iosios:scientific:scientific或或iosios:fixed:fixed时,精度时,精度npnp指小数点后的位指小数点后的位数,否则指有效数字。数,否则指有效数字。(6) (6) iosios:width:width intint width( width( int nwint nw ); ); 设置当前被显示数据的域宽设置当前被显示数据的域宽nwnw并返回原域宽。默认值并返回原域宽。默认值为为0 0,将按实际需要的域宽进行输出。此设置只对随后的一,将按实际需要的域宽进行输出。此设置只对随后的一个数据有效,而后系统立刻恢复域宽为系统默认值个数据有效,而后系统立刻恢复域宽为系统默认值0 0。20 2. 2. 常用的输入输出格式控制符常用的输入输出格式控制符 可直接用于提取和插入算符可直接用于提取和插入算符(“”(“”和和“”)“”)之后,而之后,而不像格式控制成员函数那样必须被单独调用。不像格式控制成员函数那样必须被单独调用。 (1) (1) iostreamiostream.h.h中含有的无参格式控制符中含有的无参格式控制符( (参看参看p237)p237):. . endlendl. ends. ends. flush. flush. . wsws. . decdec. hex. hex. . octoct21 (2) (2) iomanipiomanip.h.h中含有的有参格式控制符中含有的有参格式控制符( (参看参看p237)p237): . . setbasesetbase( ( intint base ) base ). . resetiosflagsresetiosflags( long ( long lFlagslFlags ) ). . setiosflagssetiosflags( long ( long lFlagslFlags ) ). . setfillsetfill( char ( char cFillcFill ) ). . setprecisionsetprecision( ( int npint np ) ). . setwsetw( ( int nwint nw ) )22 10.3.2 10.3.2 输入输出格式控制示例输入输出格式控制示例 1. 格式控制示例一格式控制示例一 ( flags和和setf等函数的功能等函数的功能) #include void main() coutios basefield; /输出:输出:112 cout (ios:dec|ios:oct|ios:hex)endl; /输出:输出:112 coutios:adjustfield; /输出:输出:14 cout (ios:left|ios:right|ios:internal)endl; /输出:输出:14 coutios:floatfield; /输出:输出:6144 cout (ios:scientific|ios:fixed)endl; /输出:输出:614423/flags将重新设置标志字,将重新设置标志字,“替换替换”方式方式 cout.flags(ios:showbase); coutcout.flags()endl; /输出:输出:128 cout.flags(ios:showpoint); coutcout.flags()endl; /输出:输出:256 cout.unsetf(ios:showpoint); coutcout.flags()endl; /输出:输出:0 /setf为为“添加添加”方式方式 cout.setf(ios:showbase); coutcout.flags()endl; /输出:输出:128 cout.setf(ios:showpoint); coutcout.flags()endl; /输出:输出:384 cout.unsetf(ios:showpoint); coutcout.flags()endl; /输出:输出:128 242. 格式控制示例二格式控制示例二 对输出数据的宽度、精度等方面进行设置与使用。对输出数据的宽度、精度等方面进行设置与使用。#include void main() cout.width(6); /只管随后一个数的域宽只管随后一个数的域宽 cout478527.4272endl; / 478527.4272coutsetw(6)4785setw(8)27.4272endlendl; / 4785 27.4272cout.width(6);cout.precision(3); /当格式为当格式为ios:scientific或或ios:fixed时,浮点数精度时,浮点数精度 /np指小数点后的位数,否则指有效数字指小数点后的位数,否则指有效数字 /此时设置浮点数的有效数字为此时设置浮点数的有效数字为3cout4785setw(8)27.4272endl; / 4785 27.4 25coutsetw(6)4785setw(8)setprecision(2)27.4272endlendl; / 4785 27 /“setprecision(2)”设置浮点数的有效数字设置浮点数的有效数字cout.setf(ios:fixed, ios:floatfield); /今后以定点格式显示浮点数今后以定点格式显示浮点数(无指数部分无指数部分)cout.width(6); cout.precision(3); /当格式为当格式为ios:fixed时,设置小数点后的位数时,设置小数点后的位数cout4785setw(8)27.4272 = 读写操作读写操作 = = 关闭文件关闭文件。 27 “打开文件打开文件”通常通过构造函数自动完成(也可显式调通常通过构造函数自动完成(也可显式调用成员函数用成员函数openopen完成)。完成)。“关闭文件关闭文件”通常通过使用通常通过使用“.close();”close();”来显式完成。来显式完成。 例例1: 1: ofstreamofstream outfile1(myfile1.txt); outfile1(myfile1.txt); 创建创建ofstreamofstream类的对象类的对象outfile1outfile1;使流类对象使流类对象outfile1outfile1与与磁盘文件磁盘文件 myfile1.txtmyfile1.txt相联系;并打开用于相联系;并打开用于“写写”的磁盘的磁盘文件文件 myfile1.txtmyfile1.txt。 例例2: 2: ofstreamofstream outfile1; outfile1; / /创建创建ofstreamofstream类的对象类的对象outfile1outfile1 outfile1.open(myfile1.txt); outfile1.open(myfile1.txt); / /显式调用成员函数显式调用成员函数openopen来打开文件来打开文件28 二二. 与创建流类对象相关的三个构造函数与创建流类对象相关的三个构造函数 1. ifstream:ifstream ifstream( const char* szName, int nMode = ios:in, int nProt = filebuf:openprot ); 参数参数: (1) szName - 文件名;文件名; (2) nMode - 打开文件的方式。打开文件的方式。 ios:in - 以读以读(输入输入)为目的打开。为目的打开。 ios:nocreate - 仅打开一个已存在文件。仅打开一个已存在文件。 ios:binary - 打开二进制文件。打开二进制文件。 (3) nProt - 指定所打开文件的保护方式。指定所打开文件的保护方式。29 2. ofstream:ofstream ofstream( const char* szName, int nMode = ios:out, int nProt = filebuf:openprot ); 参数参数: (1) szName - 文件名;文件名; (2) nMode - 打开文件的方式。打开文件的方式。 ios:out - 以写以写(输出输出)为目的打开文件。为目的打开文件。 ios:trunc - 若文件存在,则将文件长度截为若文件存在,则将文件长度截为0。 ios:binary - 打开二进制文件。打开二进制文件。 ios:app - 以追加方式打开。以追加方式打开。 . (3) nProt - 指定所打开文件的保护方式。指定所打开文件的保护方式。 30 3. fstream:fstream fstream( const char* szName, int nMode, int nProt = filebuf:openprot ); 参数含义和用法与参数含义和用法与ofstream构造函数处相同。构造函数处相同。 三三. 与创建流类对象相关的三个与创建流类对象相关的三个open函数函数 1. ofstream:open void open( const char* szName, int nMode = ios:out, int nProt = filebuf:openprot ); 2. ifstream:open void open( const char* szName, int nMode = ios:in, int nProt = filebuf:openprot ); 3. fstream:open void open( const char* szName, int nMode, int nProt = filebuf:openprot ); 3110.4.2 读写操作示例读写操作示例 - - 参看书参看书p246, 10.6.2p246, 10.6.2小节的小节的1 1 对文件的对文件的“读写操作读写操作”通常使用预定义的通常使用预定义的类成员函数类成员函数来实现(随后介绍),但也可使用继承而来的来实现(随后介绍),但也可使用继承而来的插入和提取运插入和提取运算符算符“”“”和和“”“”operator ”,所以,所以,ifstreamifstream流(类对象)可以使用预定义的算符流(类对象)可以使用预定义的算符“”“”来对自来对自定义磁盘文件进行定义磁盘文件进行“读读”操作(允许通过派生类对象直接调操作(允许通过派生类对象直接调用其基类的公有成员函数);用其基类的公有成员函数); ofstreamofstream类由类由ostreamostream类所派生类所派生,而,而ostreamostream类中预定义类中预定义了公有的运算符了公有的运算符重载函数重载函数“operator ”operator ”,所以,所以,ofstreamofstream流(类对象)可以使用预定义的算符流(类对象)可以使用预定义的算符“”“”“”和和“”“”来对自定义磁盘文件进行来对自定义磁盘文件进行“读读” ” 与与“写写”操作。操作。 还有一点需要注意:使用预定义的算符还有一点需要注意:使用预定义的算符“”“”“”来进行来进行“读读”操作操作时遇空格或换行均结束一个数据相呼应。时遇空格或换行均结束一个数据相呼应。 下述下述示例程序示例程序做了如下的做了如下的3 3件事:件事:1)1) 往文件写数据;往文件写数据;2)2) 往文件尾部追加数据;往文件尾部追加数据; 3)3) 从文件读出数据并显示在屏幕上。从文件读出数据并显示在屏幕上。 33#include void main() /1) 往文件写数据往文件写数据ofstream outfile1(myfile1.txt); /以以“写写”方式打开方式打开outfile1Hello!.CHINA! Nankai_Universityendl; outfile1.close(); /2) 往文件尾部追加数据往文件尾部追加数据 outfile1.open(myfile1.txt, ios:app); /以以“追加追加”方式打开方式打开int x=1212, y=6868;outfile1x ystr1str2; /使用使用“”读读(遇空格、换行均结束遇空格、换行均结束)infile1x2y2;infile1.close(); 34coutstr1=str1endl;coutstr2=str2endl;coutx2=x2endl;couty2=y2endl; 程序执行后的显示结果如下:程序执行后的显示结果如下:str1=Hello!.CHINA!str2=Nankai_Universityx2=1212y2=686835 10.5 10.5 使用类成员函数对文件流进行操作使用类成员函数对文件流进行操作10.5.1 10.5.1 类成员函数类成员函数getget与与putput10.5.2 10.5.2 类成员函数类成员函数readread与与writewrite10.5.3 10.5.3 类成员函数类成员函数getlinegetline 3610.5.1 10.5.1 类成员函数类成员函数getget与与putput- - 参看书参看书p247, 10.6.2p247, 10.6.2小节的小节的2 2 ostreamostream& put( char & put( char chch ); );功能:将字符功能:将字符chch写到自定义文件中。写到自定义文件中。 istreamistream& get( char& & get( char& rchrch ); );功能:从自定义文件中读出功能:从自定义文件中读出1 1个字符放入引用个字符放入引用rchrch中。中。 注意,注意,putput实际上只是实际上只是ostreamostream类中定义的公有成员类中定义的公有成员函数,当然通过其派生类函数,当然通过其派生类ofstreamofstream的类对象也可以直接的类对象也可以直接对它进行调用。同理,通过对它进行调用。同理,通过ifstreamifstream的类对象可以直接的类对象可以直接调用调用getget。37 1. 程序示例一程序示例一 从键盘输入任一个字符串,通过从键盘输入任一个字符串,通过put将其写到自定义磁盘文件将其写到自定义磁盘文件“putgetfile.txt”中,而后再使用中,而后再使用get从该文件中读出所写串并显示在屏幕上。从该文件中读出所写串并显示在屏幕上。 #include #include void main() /键盘输入字符串,通过键盘输入字符串,通过put将其写到自定义磁盘文件中将其写到自定义磁盘文件中char str80;coutInput string:endl;gets(str);ofstream fout(putgetfile.txt); int i=0;while ( stri ) fout.put(stri+); fout.close();cout-endl;38 /而后使用而后使用get从文件中读出该串显示在屏幕上从文件中读出该串显示在屏幕上char ch;ifstream fin(putgetfile.txt); fin.get(ch);while(!fin.eof() /从头读到文件结束从头读到文件结束(当前符号非文件结束符时继续当前符号非文件结束符时继续) /注注: 成员函数成员函数eof()在读到文件结束时方返回在读到文件结束时方返回true coutch; fin.get(ch);coutendl;fin.close(); 程序执行后的显示结果如下:程序执行后的显示结果如下:Input string:File operating - using put and get, OK! 12345-File operating - using put and get, OK! 1234539 2. 程序示例二程序示例二 - 对指定文件进行拷贝对指定文件进行拷贝 使用类成员函数使用类成员函数get与与put对指定文件进行拷贝。被拷贝对指定文件进行拷贝。被拷贝的的“源文件源文件”以及拷贝到的以及拷贝到的“目的文件目的文件”的名字与路径均由的名字与路径均由命令行参数来提供。命令行参数来提供。 程序执行结果程序执行结果(若提供的命令行参数为若提供的命令行参数为:mycopy.cpp res_1.cpp): Copy file from mycopy.cpp to res_1.cpp 程序执行结果程序执行结果(若提供的命令行参数个数不对时若提供的命令行参数个数不对时):ERROR ! - supplying 2 command-line argements ?!40 #include #include void main(int argc, char* argv) if(argc!=3) /命令行参数个数不对时命令行参数个数不对时 coutERROR ! - supplying 2 command-line argements ?!endl; exit (1); coutCopy file from argv1 to argv2endl; ifstream fin(argv1); /命令行参数命令行参数1作为文件名作为文件名 ofstream fout(argv2); /命令行参数命令行参数2作为文件名作为文件名 char ch; fin.get(ch); while(!fin.eof() /从头读到文件结束从头读到文件结束 fout.put(ch); fin.get(ch); fin.close(); fout.close(); 4110.5.2 10.5.2 类成员函数类成员函数readread与与write write - - 参看书参看书p247, 10.6.2p247, 10.6.2小节的小节的2 2 通常使用通常使用read与与write对二进制文件对二进制文件(binary file)进行读写。进行读写。 ostream& write( const char* pch, int nCount ); 功能:将功能:将pch缓冲区中的前缓冲区中的前nCount个字符写出到某个文件中。个字符写出到某个文件中。istream& read( char* pch, int nCount ); 功能:从某个文件中读入功能:从某个文件中读入nCount个字符放入个字符放入pch缓冲区中缓冲区中(若读至文件结束尚不足(若读至文件结束尚不足nCount个字符时,也将立即结束个字符时,也将立即结束本次读取过程)。本次读取过程)。 注意:使用注意:使用write与与read进行数据读写时,不必要在数据进行数据读写时,不必要在数据间再额外间再额外“插入插入”分割符,这是因为它们都要求提供第二分割符,这是因为它们都要求提供第二实参来指定读写长度。实参来指定读写长度。42 以下的示例程序先使用以下的示例程序先使用write往自定义二进制磁盘文件往自定义二进制磁盘文件中写出如下中写出如下3个个“值值”:字符串:字符串str的长度值的长度值Len(一个正整一个正整数数)、字符串、字符串str本身、以及一个结构体的数据,而后再使用本身、以及一个结构体的数据,而后再使用read读出这些读出这些“值值”并将它们显示在屏幕上并将它们显示在屏幕上。 #include #include void main() char str20=Hello world!;struct stuchar name20;int age;double score; ss=wu jun, 22, 91.5; 43 coutWRITE to wrt_read_file.binendl;ofstream fout(wrt_read_file.bin, ios:binary); /打开用于打开用于“写写”的二进制磁盘文件的二进制磁盘文件int Len=strlen(str);fout.write( (char*)(&Len), sizeof(int) ); fout.write(str, Len); /数据间无需分割符数据间无需分割符fout.write(char*)(&ss), sizeof(ss); fout.close();cout-endl;cout- READ it from wrt_read_file.bin -endl;char str280;ifstream fin(wrt_read_file.bin, ios:binary); fin.read( (char*)(&Len), sizeof(int) );fin.read(str2, Len);str2Len=0; 44 fin.read( (char*)(&ss), sizeof(ss) ); coutLen=Lenendl; coutstr2=str2endl; coutss.name,ss.age,ss.scoreendl; fin.close(); cout-wu jun,22,91.5-45 最常用格式为:最常用格式为:istream& getline( char* pch, int nCount, char delim = n ); 功能:从某个文件中读出一行功能:从某个文件中读出一行(至多至多nCount个字符个字符)放入放入pch缓冲区中,缺省行结束符为缓冲区中,缺省行结束符为n。 程序实例程序实例: 读出读出“getline_1.cpp”的各行并显示在屏幕上(如,可的各行并显示在屏幕上(如,可将本源程序存放在将本源程序存放在“getline_1.cpp“文件中)。文件中)。 10.5.3 10.5.3 类成员函数类成员函数getline getline - - 注,书中没介绍该函数注,书中没介绍该函数 46 #include void main() char line81; ifstream infile(“getline_1.cpp”); /打开文件用于读打开文件用于读 infile.getline(line, 80); /读出一行读出一行(至多至多80个字符个字符)放入放入line中中 while(!infile.eof() /尚未读到文件结束则继续循环尚未读到文件结束则继续循环(处理处理) coutlineendl; /显示在屏幕上显示在屏幕上 infile.getline(line,80); /再读一行再读一行 infile.close();47 10.6 text文件与文件与binary文件文件10.6.1 对对text文件与文件与binary文件的一般使用示例文件的一般使用示例10.6.2 采用采用binary文件形式对结构体数据文件形式对结构体数据进行存储与读写处理进行存储与读写处理- 10.6.1 对对text文件与文件与binary文件的一般使用示例文件的一般使用示例 * 以以text形式存储形式存储,优点优点是具有较高的兼容性。是具有较高的兼容性。缺点缺点是是存储一批纯数值信息时,要在数据之间人为地添加分割符;存储一批纯数值信息时,要在数据之间人为地添加分割符;输入输出过程中,系统要对内外存的数据格式进行相应转输入输出过程中,系统要对内外存的数据格式进行相应转换;另外换;另外text文件不便于对数据实行随机访问。文件不便于对数据实行随机访问。48 * * 以以binarybinary形式存储形式存储,优点优点是便于对数据实行随机访是便于对数据实行随机访问(每一同类型数据所占磁盘空间的大小均相同,不必在问(每一同类型数据所占磁盘空间的大小均相同,不必在数据之间人为地添加分割符);输入输出过程中,系统不数据之间人为地添加分割符);输入输出过程中,系统不对数据进行任何转换。对数据进行任何转换。缺点缺点是兼容性低。是兼容性低。 注:由程序员决定将数据存储为注:由程序员决定将数据存储为texttext文件或者文件或者binarybinary文文件两种形式之一。件两种形式之一。 缺省打开方式时,默认为缺省打开方式时,默认为texttext文件形式。若欲使用文件形式。若欲使用binarybinary文件形式,要将打开方式设为文件形式,要将打开方式设为“iosios:binary”:binary”。 通常将纯文本信息(如字符串)以通常将纯文本信息(如字符串)以texttext文件形式存储,文件形式存储,而将数值信息以而将数值信息以binarybinary文件形式存储。文件形式存储。 49 1. 1. 示例示例1 - 1 - 对两种文件进行操作对两种文件进行操作 将将a a数组中准备好的数组中准备好的8 8个个intint型数据,分别通过算符型数据,分别通过算符“”“”依次写出到依次写出到texttext文件文件ft.txtft.txt之中(注意各数据在文件中之中(注意各数据在文件中“长短长短”不一,且数据间必须加入分割符)。而且还通过不一,且数据间必须加入分割符)。而且还通过使用类成员函数使用类成员函数writewrite将这相同的将这相同的8 8个个intint型数据依次写出到型数据依次写出到binarybinary文件文件fbfb.bin.bin之中(注意各数据在文件中之中(注意各数据在文件中“长短长短”相相同,且数据间不需要加入分割符)。同,且数据间不需要加入分割符)。 另外,程序中通过使用无参的成员函数另外,程序中通过使用无参的成员函数“tellptellp()”()”来来获取当前已写出到各文件的位置信息,以确认每一数据在获取当前已写出到各文件的位置信息,以确认每一数据在文件中所占的字节数。文件中所占的字节数。 ostreamostream:tellptellp之功能为:获取并返回之功能为:获取并返回“输出指针输出指针”的当前位置值(从文件首到当前位置的字节数)。的当前位置值(从文件首到当前位置的字节数)。 50 #include void main() int a8=0,1,-1,1234567890; for(int i=4; i8; i+) ai=876543210+i-4; /均由均由9位数字组成,在位数字组成,在text文件中所占字节数也为文件中所占字节数也为9 ofstream ft(ft.txt); ofstream fb(fb.bin, ios:binary); for(i=0; i8; i+) ftai ;/数据间需要添加分割符数据间需要添加分割符 fb.write(char*)(&ai), sizeof(ai); /数据间不需分割符数据间不需分割符 coutft.tellp()=ft.tellp(), ; /当前当前ft文件位置文件位置 coutfb.tellp()=fb.tellp()endl; /当前当前fb文件位置文件位置 ft.close(); fb.close(); 51 程序执行后的输出结果如下:程序执行后的输出结果如下:ft.tellp()=2, fb.tellp()=4ft.tellp()=4, fb.tellp()=8ft.tellp()=7, fb.tellp()=12ft.tellp()=18, fb.tellp()=16ft.tellp()=28, fb.tellp()=20ft.tellp()=38, fb.tellp()=24ft.tellp()=48, fb.tellp()=28ft.tellp()=58, fb.tellp()=3252 *2. 示例示例2 - 使用使用read与与write对对text文件进行操作时可能出错文件进行操作时可能出错 具体程序从略。具体程序从略。 评注:评注: (1)通常使用通常使用read与与write对二进制文件进行操作,但若非要使用它们对文对二进制文件进行操作,但若非要使用它们对文本文件进行操作时,系统在本文件进行操作时,系统在write时有可能多写出了一些东西(如,回车换行时有可能多写出了一些东西(如,回车换行符号等)。这样将导致符号等)。这样将导致read时产生错误。时产生错误。 (2)read与与write功能的进一步解释:功能的进一步解释: istream:read Extracts bytes from the stream until the limit nCount is reached or until the end of file is reached. The read function is useful for binary stream input. ostream:write Inserts a specified number of bytes from a buffer into the stream. If the underlying file was opened in text mode, additional carriage return characters may be inserted. The write function is useful for binary stream output. 5310.6.2 10.6.2 采用采用binarybinary文件形式对结构体文件形式对结构体 数据进行存储与读写处理数据进行存储与读写处理 从键盘读入多个结构数据从键盘读入多个结构数据(个数个数n由用户指定由用户指定),使用,使用write将这些结将这些结构数据写出到某个自定义二进制磁盘文件中,而后再使用构数据写出到某个自定义二进制磁盘文件中,而后再使用read读出这些读出这些结构数据并进行处理结构数据并进行处理(如,求出如,求出n个个score的平均值的平均值ave)。#include void main() struct person char name 20; int age; float score; ss;int n;cinn; /个数个数n由用户指定由用户指定54 ofstream fout(f01.bin, ios:binary); /打开二进制文件(写)打开二进制文件(写) for(int i=0; iss.namess.agess.score; fout.write( (char *)(&ss), sizeof(ss); /写到文件中写到文件中 fout.close();
展开阅读全文