第七章C++的I、O流类库_第1页
第七章C++的I、O流类库_第2页
第七章C++的I、O流类库_第3页
第七章C++的I、O流类库_第4页
第七章C++的I、O流类库_第5页
已阅读5页,还剩49页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第七章

C++的I/O流类库

7.1 C++为何建立自己的输入输出系统

C++除了完全支持C语言的输入输出系统外,还定义了一套面向对象的输入输出系统。为什么C++还要建立自己的输入输出系统呢?C语言的输入输出系统不支持用户自定义的对象,如:Structmy_struct{

inti;floatf;char*str;}s;对此结构类型,在C语言中下面的语句是不能接受的:

printf(“%my_struct”,s);

因为printf()函数只能识别系统预定义的类型,而没有办法对新的数据类型进行扩充.。用C++的输入输出系统,就可以通过重载“<<”和“>>”运算符来解以上问题。C++的类机制允它建立一个可扩展的输入输出系统,它可以通过修改和扩展来加入用户自定义类型及相应操作。17.2C++的流及流类库7.2.1C++的流

输入输出是一种数据传递操作,它可以看作字符序列在主机与外部介质之间的流动。流(stream)为从源(或生产者)到目的(或消费者)的数据流的引用。流具有方向性:与输入设备(如键盘)相联系的流称为输入流;与输出设备(如屏幕)相联系的流称为输出流;与输入输出设备(如磁盘)相联系的流称为输入输出流。

C++中包含几个预定义的流:标准输入流cin与标准输入设备相关联标准输出流cout与标准输出设备相关联非缓冲型标准出错流cerr与标准错误输出设备相关联(非缓冲方式)缓冲型的标准出错流

clog与标准错误输出设备相关联(缓冲方式)在缺省情况下,指定的标准输出设备是显示终端,标准输入设备是键盘。在任何情况下(有时用户把标准输出设备定向为其它设备),指定的标准错误输出设备总是显示终端。cerr<<“Theaveragecannotbecomputed.\n”;27.2.2流类库

C++流类库是用继承方法建立起来的一个输入输出类库。它具有两个平行的基类:streambuf类,

ios

类。所有其它的流类都是从它们直接或间接地派生出来的。使用C++的流类库,程序中可能应包含的头文件:

iostream.hstrstream.hfstream.hiomanip.h1.streambuf

类streambuffilebufstrstreambufconbuf派生32.

ios类iosfstreambasestrstreambaseostreamistreamistrstreamofstreamostrstreamconstreamifstreamfstreamistream_withassignostream_withassigniostream_withassignstrstreamiostream47.3输入输出的格式控制7.3.1用ios类的成员函数进行格式控制

ios类中有几个成员函数可以用来对输入输出进行格式控制。主要控制状态标志字、域宽、填充字符及输出精度。1.状态标志字状态标志存放在数据成员

longx_flags

中。ios

类public中定义了一个枚举,它的每个成员可以分别定义状标志字的一个位,每一位都称为一个状标志位。

5.这个枚举定义如下:enum{0000

0000

0000

0001skipws=0x0001,跳过输入中的空白,可用于输入left=0x0002,左对齐输出,可用于输出right=0x0004,右对齐输出,可用于输出internal=0x0008,在符号位和基指示符后填入字符,可用于输出dec=0x0010,转换基数为十进制,可用于输入或输出oct=0x0020,转换基数为八进制,可用于输入或输出hex=0x0040,转换基数为十六进制,可用于输入或输出showbase=0x0080,在输出时显示基指示符,可于输入或输出showpoint=0x0100,在输出时显示小数点,可用于输出uppercase=0x0200,十六进制输出时,表示制式的和表示数值的字符一律为大写,可用于输出showpos=0x0400,正整数前显示”+”符号,可用于输出scientific=0x0800,用科学表示法显示浮点数,可用于输出fixed=0x1000,用定点形式显示浮点数,可用于输出unitbuf=0x2000,在输出操作后立即刷新所有流,可用于输出

stdio=0x4000,在输出操作后刷新stdout和stderr,可用于输出};62x_flags取以上枚举值的并存,即x_flags上的每一位(长整数为16位)中的01相当于一个枚举值。例如x_flags中放0x0011或17即为0000

0000

0001

0001相当于0x0001与0x0010之并skipws(0x0001)0000000000000001dec(0x0010)+0000000000010000x_flags(0x0011)000000000001000172. ios类中用于控制输入输出格式的成员函数函数原型功能longios::setf(longflags);设置状态标志flagslongios::unsetf(longflags);清除状态标志,并返回前标志longios::flags();

测试状态标志longios::flags(longflags);设置标志flags,并返回前标志intios::width();

返回当前的宽度设置值intios::width(intw);

设置域宽w,返回以前的设置intios::precision(intp);

设置小数位数p返回以前的小数位数charios::fill();

返回当前的填充字符charios::fill(charch);设置填充字符ch返回当前的填充字符8(1)设置状态标志

设置状态标志,即是将某一状态标志位置“1”,可使用setf()函数其一般的调用格式为:流对象.setf(ios::状态标志);

例7.1#include<iostream.h>main(){istreamcin;//对象cin可不定义

ostreamcout;//对象cout可不定义

cin.setf(ios::shipws);//键盘输入时跳过输入空白

cout.setf(ios::left);//设置输出左对齐cout.setf(ios::showpos|ios::sciengific);//中间用运算符“|”分隔

cout<<567<<“”<<567.89<<endl;}设置showpos使得每个正数前添加“+”号,设置sciengific使浮点数按科学表示法(指数形式)进行显示,输出结果:+567+567.89e02注意:要设置多项标志时,中间用或运算符“|”分隔。

9(2)清除状态标志

清除某一状态标志,即是将某一状态标志位置”0”,可使用unseft()函数,使用时的调用格式与setf()相同。(3)取状态标志取一个状态标志,可使用flags()函数。flags()函数有不带参数与带参数两种形式:

lingios::flags();用于返回当前的状态标志字;

lingios::flags(liogflag);返回当前的状态标志字后,再者将状态标志字设置成flag(参数)。flags(liogflag)函数与setf(liogflags)函数的差别在于:setf()函数是在原有的基础上追加设定的,而flags()函数是用新设定覆盖以前的状态标志字。例7.2几个成员函数的使用方法#include<iostream.h>voidshowflags(longf)//输出状态标志字函数{longi;for(i=0x8000;i;i=i>>1)//用右移方法使i中的值为”1”的位不断右移

if(i&f)cout<<”1”;//判断f中的某一位是否为”1”

elsecout<<”0”;cout<<endl;}10接1例7.2voidmain(){longf;

cout.setf(ios::unitbuf|ios::skipws);f=cout.flags();//取当前状态标志字

showflags(f);//显示状态标志字

cout.setf(ios::showpos|ios::scientific);//追加状态标志位

f=cout.flags();showflags(f);cout.unsetf(ios::scientific);//从状态标志字中去掉sciengific

f=cut.flags();showflags(f);f=cout.flags(ios::oct);//重新设置状态标志字

showflags(f);//显示设置前的状态标志字

f=cout.flags();//取设置后的状态标志字

showflags(f);//显示设置后的状态标志字}11程序运行结果为;

0010000000000001(1)

0010110000000001(2)

0010010000000001(3)

0000000000100000(4)

0000000000100000(5)(4)设置域宽

域宽主要用来控制输出,在ios类中域宽存放在数据成员intx_width中,设置域宽的成员函数有两个,其一般格式为:

intios::width();返回当的域宽值

intios::width(intw);设置域宽,并返回原来的域宽(5)设置输出的精度精度用来控制浮点数的输出显示精度,在ios类中用数据成员intx_precision来存放精度,设置精度的成员函数的一般格式为:

intios::precision(intp);重新设置浮点数所需小数的位数,并返回设置前的位数(6)填充字符填充字符的作用是:当输出值不满域宽时用填充字符来填充,缺省情况下填充字符为空格,所以在使用填充字符函数时,必须与width()函数相配合,否则就没有意义,在ios类中用数据成员x_fill来存放填充字符。填充字符的成员函数有两个,其一般形式为:charios::fill();返回当的填充字符

charios::fill(charch);用ch重新设置填充字符,并返回设置前的填充字符。12例7.3#include<iostream.h>voidmain(){cout<<”x_width=”<<cout.width()<<endl;

cout<<”x_fill=”<<cout.fill()<<endl;

cout<<”x_precision=”<<cout.precision()<<endl;

cout<<123<<”“<<123.45678<<endl;

cout<<”---------------------------------------\n”;

cout<<”****x_width=10,x_fill=,x_precision=4****\n”;

cout.width(10);

cout.precision(4);

cout<<123<<”“<<123.45678<<”“<<234.567<<endl;

cout<<”x_width=”<<cout.width()<<endl;

cout<<”x_fill=”<<cout.fill()<<endl;

cout<<”x_precision=”<<cout.precision()<<endl;

cout<<”---------------------------------------\n”;

cout<<”****x_width=10,x_fill=&,x_precidion=4****\n”;

13接1例7.3

cout.fill(‘&’);

cout.width(10);

cout<<123<<”“<<123.45678<<endl;

cout.setf(ios::left);

cout.width(10);

cout<<123<<”“<<123.45678<<endl;

cout<<”x_width=”<<cout.width()<<endl;

cout<<”x_fill=”<<cout.fill()<<endl;

cout<<”x_precision=“<<cout.precision()<<endl;}14程序运行结果如下:

x_width=0

x_fill=

x_precision=0

123 123.45678

-------------------------------------****x_width=10,x_fill=,x_preciosion=4****

123123.4568234.567

x_width=0

x_fill=

x_precision=4

-------------------------------------****x_width=10,x_fill=&,x_precision=4****&&&&&&&123123.4568

123&&&&&&&123.4568

x_width=0

x_fill=&

x_precision=4例7.4利用控制输入输出格式的成员函数建立对齐的数字表#include<iostream..h>#include<math.h>voidmain(){doublex;cout,precision(4);cout<<”xsqrt(x)x^2\n\n”;for(x=1.0;x<=20.0;x++){cout.width(8);cout<<x<<’‘;cout.width(8);cout<<sqrt(x)<<’‘;cout.width(8);cout<<x*x<<’\n’;}}这程序建立了如下的表

xsqrt(x)x^2

11121.41424

31.7321

9

4

2

16

52.236125

62.4495

36

72.6458

49

82.8284

64

93

81

103.1623

100

113.3166121

123.4641144

133.6056169

143.7417196

153.873225

16 4256

174.1231289

184.2426324

194.3598361

204.4721400157.3.2使用操作符进行输入输出格式控制

C++提供了另一种进行I/O格式控制的方法,这一方法使用了一种称为操纵符(也称为操纵函数)的特殊函数。在很多情况下,使用操纵符进行格式化控制比用ios格式标志和成员函数要方便。1.C++预定义的操纵符

C++预定义的操纵符是以一个流引用作为其参数,并返回同一流的引用,因此它可以嵌入到输入输出操作的链中。操纵符可用来改变域宽,使整型数以八进制或十六进制形式输入或输出,并设置填充字符等。许多操纵符的功能类似于上面介绍的ios类成员函数的功能。C++提供的预定义操纵符如下:(1)

dec以十进制形式输入或输出整型数,可用于输入或输出。(2)hex

以十六进制形式输入或输出整型数,可用于输入或输出。(3)oct以八进制形式输入或输出整型数,可用于输入或输出。(4)ws用于在输入时跳过开头的空白符,仅用于输入。(5)endl插入一个换行符并刷新输出流,仅用于输出。(6)ends插入一个空字符,通常用来结束一个字符串,仅用于输出。(7)flush刷新一个输出流,仅用于输出。(8)setbase(intn)把转换基数设置为n(n的值为0,8,10,或16),n的缺省值为”0”,即以十进制形式输出。16(9)resetiosflags(longf)关闭由参数f指定的格式标志,可用于输入或输出。(10)setiosflags(longf)设置由参数f指定的格式标志,可用于输入或输出。(11)setfill(intc)c为填充字符,缺省时为空格,可用于输入或输出。(12)setprecision(intn)设置数据小数部分的位数,缺省时小数的位数为6,可用输入输出。(13)setw(intn)设置域宽为n,可用于输入或输出。17

操纵符setiosflags()和resetiosflags()中所用的格式标志

格式标志名含义 ios::left输出数据按域宽左对齐输出 ios::right

输出数据按域宽右对齐输出 ios::scientific

使用科学计数法表示浮点数 ios::fixed

使用定点形式表示浮点数 ios::dec转换基数为十进制形式 ios::hex转换基数为十六进制形式 ios::oct转换基数为八进制形式 ios::uppercase

十六进制形式和科学计数法输出时,表示数值的字符一律为大写ios::showbase输出带有一个表示制式的字符(如”X”表示十六进制,”O”表示八进制)ios::showpos 在正数前添加一个”+”号 ios::showpoint浮点输出时必须带有一个小数点 2.操纵符的使用操纵符分为带参数的操纵符和不带参数的操纵符.通常,不带参数的操纵符在iostream.h文件中定义,带参数的操纵符在iomanip.h文件中定义。18例7.5使用操纵符的输入输出格式控制#include<iostream.h>#include<iomanip.h>voidmain(){cout<<setw(10)<<123<<567<<endl;//①cout<<123<<setiosflags(ios::scientific)<<setw(20)<<123.456789<<endl;//②cout<<123<<setw(10)<<hex<<123<<endl;//③cout<<123<<setw(10)<<oct(8)<<123<<endl;//④cout<<123<<setw(10)<<setbase(0)<<123<<endl;//⑤cout<<resetiosflags(ios::scientific)<<setprecision(4)<<123.456789<<endl;⑥cout<<setiosflags(ios::left)<<setfill(‘#’)<<setw(8)<<123<<endl;//⑦cout<<resetiosflags(ios::left)<<setfill(‘$’)<<setw(8)<<456<<endl;//⑧}19程序运行结果为: 1234567 ①1231.234567e+02 ②1237b ③7b 173 ④173123 ⑤123.4568 ⑥123##### ⑦$$$$$456 ⑧例7.6二次方表与二次方根表的程序的程序的另一个版本#include<iostream.h>#include<iomanip.h>#include<math.h>voidmain(){doublex;cout<<setprecision(4);cout<<“xsqrt(x)x^2\n\n”;for(x=1.;x<=20.0;x++);{

cout<<setw(8)<<x<<’’; cout<<setw(8)<<sqrt(x)<<’’; cout<<setw(8)<<x*x<<’n’;}}203.用户自定义的操纵符

C++除了提供此同预定义的操纵符外,也允许用户自定义操纵符,把程序中频繁使用的输入输出操作合并成一个操纵符。若为输出流定义操纵符函数,则定义形式如下:

ostream&manip_name(ostream&stream){//自定义代码

returnstream;}

若为输入流定义操纵符函数,则定义形式如下:

istream&manip_name(istream&stream){//自定义代码

returnstream;}21例7.7自定义的操纵符#include<iostream.h>#include<iomanip.h>ostream&output1(ostream&stream){stream.setf(ios::left);stream<<setw(10)<<hex<<setfill(‘&’);returnstream;}voidmain(){cout<<123<<endl;cout<<output1<<123<<endl;}程序运行结果如下:1237b&&&&&&&&22例7.8#include<iostream.h>#include<iomanip.h>istream&inputl(istream&in){cin>>hex;cout<<“Enternumberusinghexformat:”;returnin;}voidmain(){inti;cin>>inputl>>i;cout<<endl;}

以上程序中定义了一个操纵符函数input1,该函数要求输入一个十六进制数。程序运行后,屏幕上显示:

Enternumberusinghexformat:提示用户输入一个十六进制数。237.4用户自定义类型的输入输出

用户自定义的类型数据的输入或输出,可以通过重载运算符“>>”和“<<”来实现,使“>>”和“<<”可以直接用来输入或输出类的对象。7.4.1重载输出运算符“<<”定义输出运算符”<<”重载函数的一般格式如下:ostream&operator<<(ostream&stream,class_nameobj){ //操作代码

returnstream;}函数中的一个参数是对ostream对象的引用,它可以是其它任何合法的标示符,但必须与return后面的标示符相同。第二个参数接受将被输出的对象,其中class_name是类名,obj为该类的对象名。24例7.9输出运算符“<<”重载的例子#include<iostream.h>classcoord{public: intx,y; coord(){x=0;y=0;}coord(intI,intj){x=I;y=j;}};ostream&operator<<(ostream&stream,coordob){stream<<ob.x<<“,”<<ob.y<<endl;returnstream;}voidmain(){coorda(5,6),b(10,34);cout<<a<<b;}程序运行结果如下:5,610,3425例7.10把重载输出运算符定义为类的友元函数,这样就可以访问类的私有成员#include<iostream.h>classcoord{intx,y;public: coord(){x=0;y=0;}coord(inti,intj){x=i;y=j;} friendostream&operator<<(ostream&stream,coordob);};ostream&operator<<(ostream&stream,coordob){stream<<ob.x<<”,”<<ob.y<<endl;returnstream;}voidmain(){coorda(5,6),b(10,34);cout<<a<<b;}26程序运行结果如下: 5,6 10,347.4.2重载输入运算符“>>”

只是要把ostream换成istream,把”<<”用”>>”代替,第二个参数是一个引用。定义输入运算符”>>”重载函数的一般格式如下:istream&operator>>(istream&stream,class_name&obj){ //操作代码

returnstream;}例7.11重载输入运算符“>>”#include<iostream.h>classthree_d{ intx,y,z;public: three_d(inta,intb,intc){x=a;y=b;z=c;}friendostream&operator<<(ostream&output,three_dob);friendistream&operator>>(istream&input,three_d&ob);};27接1例7.11ostream&operator<<(ostream&output,three_dob);{output<<ob.x<<“,”;output<<ob.y<<“,”;output<<ob.z<<endl;returnoutput;}istream&operator>>(istream&input,three_d&ob);{cout<<”Enterx,y,zvalue:”;input>>ob.x;input>>ob.y;input>>ob.z;returninput;}28接2例7.11voidmain(){three_dobj(10,20,30); //定义类three_d的对象objcout<<obj; //输出对象obj的成员值

cin>>obj; //输出对象obj的各成员值,将原值覆盖

cout<<obj; //输出对象obj的成员值(新值)}程序运行结果如下:10,20,30

Enterx,y,zvalue:40506040,50,60297.5文件的输入输出

C++把文件看作字符序列,即文件是由一个字符数据顺序组成的。根据数据的组织形式,文件可分为文本文件和二进制文件。文本文件又称ASCII文件,它的每个字节存放一个ASCII代码,代表一个字符。二进制文件则是把内存中的数据,按其在内存中的存储形式原样写到磁盘上存放。文件是一个字符流或二进制流,它把数据看作是一连串的字符,而不考虑记录的界限,它对文件的存取以字符为单位进行。我们把这种文件称为流式文件。在C++中,要进行文件的输入输出,必须首先创建一个流,然后将这个流与文件相关联,即打开文件,此时才能进行读写操作,完成后再关闭这个文件。这是C++中进行文件输入输出的基本过程。7.5.1文件的打开与关闭1. 文件的打开为了执行文件的输入输出,C++提供了三个流类。名称基类功能

ofstream由ostream派生用于文件的输出

ifstream由istream派生用于文件的输入

fstream由iostream派生用于文件的输入或输出30建立流的过程就是定义流类的对象,例如:

ifstreamin;ofstreamout;fstreamboth;它们分别定义了输入流对象in,输出流对象out,输入输出流对象both。Open()函数是上述三个流类的成员函数,其原型为:voidopen(constunsignedchar*,intmode,

intaccess=filebuf::openprot);打开语句:流类的对象.

open(constunsignedchar*,intmode,intaccess=filebuf::openprot);

其中第一个参数是用来传递文件名的;第二个参数mode的值决定文件将如何被打开,它必须取下面的值中的一个;access的值决定文件的访问方式。

31

ios::app 使输出追加到文件尾部

ios::ate 查找文件尾

ios::in 打开一个文件进行读操作

ios::nocreate 文件不存在时,导致open()失败

ios::noreplace 若文件存在,则open()失败

ios::out 打开一个文件进行写操作

ios::trunc 使同名文件被删除

ios::binary 文件以二进制方式打开,缺省时为文本文件访问方式0普通文件1只读文件2隐含文件4系统文件8备份文件32打开文件的步骤:(1)定义一个类的对象,例如:ofstreamout;(2)使用open()函数打开文件。例如:out.open(”test”,ios::out,0);

文件只有在打开后,才能对文件进行读写操作。由于某些原因,可能打开失败,因此使用文件之前必须进行执行检测,以确认打开一个文件是否成功。可以使用类似下面的方法进行检测:if(!mystream){cout<<”cannotopenfile!\n”;//错误处理代码}在实际编程时,打开一个文件的最常见的形式为:

ofstreamout(”test”);用if(!out)检测是否打开成功它相当于语句:

ofstreamout;out.open(”test”);2.文件的关闭关闭文件可使用close()函数完成,close函数也是流类中的成员函数,它不带参数,没有返回值,例如:out.close();337.5.2文件的读写

在含有文件操作的程序中,必须有如下的预处理命令:#include<fstream.h>1.文本文件的读写文件打开后,文本文件的读写使用运算符“<<”与“>>”,只是必须用与文件相连接的流代替cin和cout。例7.12把一个整数、一个浮点数和一个字符串写到磁盘文件test中。#include<fstream.h>intmain(){ofstream

fout(”test”);if(!fout){cout<<”cannotopenoutputfile\n”;return1;}fout<<10<<””<<123.456<<”\”Thisisatestfile.\”\n”;fout.close();return0;}用“写字板”可以看到test文件的内容:10123.456“thisisatestfile”34例7.13先建立一个输出文件,向它写入数据,然后关闭文件,再按输入模式打开它,并读取信息。#include<fstream.h>voidmain(){ofstreamfout(”test2”);if(!fout){cout<<”cannotopenoutputfile.\n”;return1;}fout<<”Hello!\n”;fout<<100<<’’<<hex<<100<<endl;fout.close();ifstreamfin(”test2”);if(!fin){cout<<”cannotopeninputfile.\n”;return1;}charstr[80];intI;fin>>str>>i;cout<<str<<””<<i<<endl;fin.close();}

程序建立一个输出文件test2,并向它写入数据,关闭输出文件test2。再将文件test2按输入模式打开,并将字符串“hello!\n”读给字符数组str,将整数100读给整型变量i。最后在屏幕上显示出str和I的值,如下所示:

Hello!10035例7.14从键盘读入字符串,并将它们写进磁盘文件。当用户输入空白字符时,程序停止。#include<fstream.h>#include<stdio.h>voidmain(intargc,char*argv[]){if(argc!=2){cout<<”Usage:write<filename>\n”;return1;}ofstreamoutf(argv[1]);if(!outf){cout<<”cannotopenoutputfile.\n”;return1;}charstr[60];cout<<”Writestringstodisk,RETURNtostop\n”;do{cout<<”:”;gets(str);outf<<str<<endl;}while(*str);outf.close();}这个例子采用了命令行参数的形式,输入以下命令行:<可执行文件名><磁盘文件名>↙程序运行情况如下:Writestringstodisk,RETURNtostop:abcdefg(从键盘输入一个字符串):↙(输入空行,程序停止)程序运行后,在磁盘上生成一个名为<磁盘文件名>的文件,其内容:abcdefg362.二进制文件的读写

任何文件,无论它包含格式化的文本还是包含原始数据,都能以文本方式或二进制方式打开。文本文件是字符流,而二进制文件是字节流。(1)用get()函数和put()函数读写二进制文件

get()是输入流类istream中定义的成员函数,它可以从与流对象连接的文件中读出数据,每次读出一个字节(字符)。put()是输出流类ostream中的成员函数,它可以向与流对象连接的文件中写入数据,每次写入一个字节(字符)。get()函数有许多格式,其最一般的使用版本的原型如下:

istream&get(unsignedchar&ch);get()函数从相关流中只读一个字符,并把该值放如引用ch&中。put()函数的原型如下:

ostream&put(charch);put()函数将字符ch写入流中。37例7.15实现任意类型的文件拷贝。#include<iostream.h>#include<fstream.h>voidmain(intargc,char*argv[]){charch;if(argc!=3){cout<<”Badcommond!\n”;return0;}ifstreaminf(argv[1]);if(!inf){cout<<”Cannotopensoucefile.”;return1;}ofstreamoutf(argv[2]);if(!outf){cout<<”Cannotopentargetfile.”;return1;}while(inf){inf.get(ch);outf.put(ch);}inf.close();outf.close();}

假定本程序的文件名为mvc7_15.cpp,经编译、连接后生成的可执行文件名为mvc7_15.exe,则在DOS下输入以下命令行:

D>mvc7_15file1.exefile2.exe

该程序的执行结果,是把文件file1.exe中的信息拷贝到文件file2.exe中38eof()函数的使用

二进制文件的处理过程与文本文件的处理过程基本相同,但在判断文件是否结束时有所区别。在文本文件中,遇到文件结束符,get函数返回一个文件结束标志EOF,该标志的值为-1。但在处理二进制文件时,读入某一字节中的二进制数的值可能是-1,这与EOF的值相同。这样就有可能出现读入的有用数据被处理成“文件结束”的情况。为了解决这个问题,c++提供了一个成员函数eof,用来判断文件是否真的结束,其原型为:

inteof();

当到达文件末尾时,它返回一个非零值,否则返回零。当输入文件是键盘时,其结束符是ctrl_z,eof()函数返回的值为真。39例7.16在屏幕上显示任何给定文件的内容。#include<iostream.h>#include<fstream.h>main(intargc,char*argv[]){charch;if(argc!=2){cout<<”Usage:PR<filename>\n”;return1;}ifstreamin(argv[1]);if(!in){cout<<”Cannotopenfile”;return1;}while(!in.eof()){in.get(ch);cout<<ch;}return0;}

假定本程序的文件名为mvc7_16.cpp,经编译、连接后生成的可执行文件名为mvc7_16.exe,则在DOS下输入以下命令行:

D>mvc7_16file1

该程序的执行结果,是把文件file1中的信息在屏幕上显示。40(2)用read()函数和write()函数读写二进制文件

有时需要读写一组数据(如一个结构变量的值),为此C++提供了两个函数read()和write(),用来读写一个数据块。

①read()函数:函数原型:

istream&read(unsignedchar*buf,intnum);read()是类istream中的成员函数,其功能为:从相应的流中读取num个字节(字符),并把它们放入指针buf所指的缓冲区中。调用格式:read(缓冲区首址,读入的字节数);注意:“缓冲区首址”的数据类型为unsignedchar*,当输入其它类型数据时,必须进行类型转换,例如:intarray[]={50,60,70};定义了一个整型数组array,read((unsignedchar*)&array,sizeof(array);

对整型数组array,为了把数据从文件读入到它中,必须在read()函数中把它转换为unsignedchar*类型。由sizeof()函数确定要读入的字节数。

41②write()函数:函数原型:ostream&write(constunsignedchar*buf,intnum);write()是流类ostream的成员函数,利用该函数,可以把buf所指的缓冲区num个字节写到相应的流上。参数的含义及调用注意事项与read()函数类似。注意:如果在num个字节被读出之前就达到了文件尾,则read()只是停止执行,此时缓冲区包含这些字符。我们可以用另一个成员函数gcount()统计出有多少字符被读出。gcount()的原型如下:intgcount();它返回所读取的字节数。42例7.17用write()函数向文件test中写入双精度数与字符串。#include<iostream.h>#include<fstream.h>#include<string.h>main(){ofstreamoutf(”test”);if(!out){cout<<”cannotopenoutputfile.\n”;return1;}doublenum=100.45;charstr[]=”Thisisatest”;out.write((char*)&num,sizeof(double));out.write(str,strlen(str));out.close();return0;}

程序执行后,屏幕上不显示任何信息,但程序已将双精度100.45和字符串“thisisatest”以二进制形式写入文件test中。用下面的程序可以读取文件test中的数据,并在屏幕上显示出来,以验证前面的程序操作。43例7.18用read()函数读取例7.17中程序所建立的文件。#include<iostream.h>#include<fstream.h>#include<string.h>main(){ifstreamin(”test”);if(!in){cout<<”cannotopeninputfile.\n”;return1;}doublenum;charstr[80];in.read((char*)&num,sizeof(double));in.read(str,14);cout<<num<<’’<<str;in.close();return0;}程序运行结果为:100.45Thisisatest443.文件的随机读写前面介绍的文件操作都是按一定顺序进行读写的,因此称为顺序文件。C++在类istream及类ostream中定义了几个与在输出流中随机移动文件指针的成员函数,则可以在流内随机移动文件指针,从而可以对文件的任意数据进行随机读写。用函数seekg()和seekp()进行随机访问。函数seekg()用于输入文件,函数seekp()用于输出文件。

45它们的函数原型如下:

istream&seekg(streamoffoffset,seek_dirorigin);ostream&seekp(streamoffoffset,seek_dirorigin);其中,参数origin表示文件指针的起始位置,offset表示相对于这个起始位置的位移量。seek_dir是一个系统定义的枚举名,origin是枚举变量。origin的取值有以下三种情况:

ios::beg

从文件头开始,把文件指针移动由offset指定的距离。offset的值为正数

ios::cur

从当前位置开始,把文件指针向前(后)移动由offset指定的距离。offset的值为正或负数,正数时向前移,负数时向后移。

ios::end

从文件尾开始,把文件指针移动由offset指定的距离,offset的值为负数进行文件的随机读写时,可以用以下函数测试文件指针的当前位置:streampostellg();用于输入文件。streampostellp();用于输出文件。streampos是在iostream.h中定义的类型,实际上是long型的。46例7.19演示seekp()函数。它修改文件中的指定字符。执行时在命令行指定文件名,其后跟想修改的字符的位置,然后再跟新的字符。#include<iostream.h>#include<fstream.h>#include<stdlib.h>intmain(intargc,char*argv[]){if(argc!=4){cout<<”Usage:CHANGE<filename><byte><char>\n”;return1;}fstreamout(argv[1],ios::in|ios::out);

if(!out){cout<<”Cannotopenfile”<<argv[1]<<”\n”;return1;}out.seekp(atoi(argv[2]),ios::beg);

out.put(*argv[3]);out.close();return0;}假定上述程序的文件名为mvc7_19.cpp,经编译、连接生成的可执行文件名为mvc7_19.exe。需要修改的文件名为file,file的内容为:AAAAAAAAAA1234567890执行下述命令:D>mvc7_19file5#程序运行结果为:

AAAAA#AAAA123456789047例7.20使用seekg()函数,它从指定的位置开始显示文件内容。#include<iostream.h>#include<fstream.h>#include<stdlib.h>voidmain(intargc,char*argv[]){charch;if(argc!=3){cout<<”Usage:LOCATE<filename><loc>\n”;return1;}ifstrea

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论