1 / 54

第七章 C++ 的 I/O 流类库

第七章 C++ 的 I/O 流类库. 1. 7.1 C++ 为何建立自己的输入输出系统. C++ 除了完全支持 C 语言的输入输出系统外,还定义了一套面向对象的输入输出系统。为什么 C ++ 还要建立自己的输入输出系统呢? C 语言的输入输出系统不支持用户自定义的对象,如: struct my_struct{ int i; float f; char *str; }s; 对此结构类型 , 在 C 语言中下面的语句是不能接受的 : printf(“%my_struct”,s);

denim
Download Presentation

第七章 C++ 的 I/O 流类库

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第七章C++的I/O流类库

  2. 1 7.1 C++为何建立自己的输入输出系统 C++除了完全支持C 语言的输入输出系统外,还定义了一套面向对象的输入输出系统。为什么C ++还要建立自己的输入输出系统呢?C 语言的输入输出系统不支持用户自定义的对象,如: struct my_struct{ int i; float f; char *str; }s; 对此结构类型,在C语言中下面的语句是不能接受的: printf(“%my_struct”,s); 因为printf( )函数只能识别系统预定义的类型,而没有办法对新的数据类型进行扩充.。用C++的输入输出系统,就可以通过重载“<<”和“>>”运算符来解以上问题。 C++的类机制允它建立一个可扩展的输入输出系统,它可以通过修改和扩展来加入用户自定义类型及相应操作。

  3. 2 7.2 C++的流及流类库 7.2.1 C++的流 输入输出是一种数据传递操作,它可以看作字符序列在主机与外部介质 之间的流动。流(stream)为从源(或生产者)到目的(或消费者)的数据流的引用。流具有方向性: 与输入设备(如键盘)相联系的流称为输入流;与输出设备(如屏幕)相联系的流称为输出流;与输入输出设备(如磁盘)相联系的流称为输入输出流。 C++中包 含几个预定义的流 : 标准输入流 cin 与标准输入设备相关联 标准输出流 cout 与标准输出设备相关联 非缓冲型标准出错流 cerr 与标准错误输出设备相关联(非缓冲方式) 缓冲型的标准出错流 clog 与标准错误输出设备相关联(缓冲方式) 在缺省情况下,指定的标准输出设备是显示终端,标准输入设备是键盘。 在任何情况下(有时用户 把标准输出设备定向为其它设备),指定的标准错误输出设备总是显示终端。 cerr<<“The average cannot be computed.\n”;

  4. 3 7.2.2 流类库 C++流类库是用继承方法建立起来的一个输入输出类库。它具有两个平行的基类:streambuf 类,ios 类。所有其它的流类都是从它们直接或间接地派生出来的。使用C++的流类库,程序中可能应包含的头文件: iostream.h strstream.h fstream.h iomanip.h 1. streambuf 类 streambuf 派生 filebuf strstreambuf conbuf

  5. 4 ios 2. ios 类 istream fstreambase strstreambase ostream ifstream istrstream ofstream ostrstream constream ostream_withassign istream_withassign fstream strstream iostream iostream_withassign

  6. 5 7.3输入输出的格式控制 7.3.1 用ios 类的成员函数进行格式控制 ios类中有几个成员函数可以用来对输入输出进行格式控制。 主要控制 状态标志字、域 宽、填充字符及输出精度。 1. 状态标志字 状态标志存放在数据成员 long x_flags中。ios 类 public 中定义了一个枚举,它的每个成员可以分别定义状标志字的一个位,每一位都称为一个状标志位。

  7. 6 . 这个枚举 定义 如下: enum{ 0000000000000001 skipws =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,可用于输出 };

  8. 7 2 x_flags取以上枚举值的并存,即x_flags上的每一位(长整数为16位)中的0 1相当于一个枚举值。例如 x_flags 中放 0x0011 或 17即为 0000000000010001相当于 0x0001 与 0x0010 之并 skipws(0x0001) 0000 0000 0000 0001 dec (0x0010) + 0000 0000 0001 0000 x_flags (0x0011) 0000 0000 0001 0001

  9. 8 2. ios类中用于控制输入输出格式的成员函数 函数原型 功能 long ios::setf(long flags); 设置状态标志flags long ios::unsetf(long flags); 清除状态标志,并返回前标志 long ios::flags(); 测试状态标志 long ios::flags(long flags); 设置标志flags,并返回前标志 int ios::width(); 返回当前的宽度设置值 int ios::width(int w); 设置域宽w,返回以前的设置 int ios::precision(int p); 设置小数位数p返回以前的小数位数 char::iosfill(); 返回当前的填充字符 char::iosfill()char ch; 设置填充字符ch返回当前的填充字符

  10. 9 (1)设置状态标志 设置状态标志,即是将某一状态标志位置“1”,可使用setf()函数 其一般的调用格式为:流对象.setf(ios::状态标志); 例7.1 #include<iostream.h> main() { istream cin; //对象cin可不定义 ostream cout; //对象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 注意:要设置多项标志时,中间用或运算符 “|” 分隔。

  11. 10 (2)清除状态标志 清除某一状态标志,即是将某一状态标志位置”0”,可使用unseft()函数,使用时的调用格式与setf()相同。 (3)取状态标志 取一个状态标志,可使用 flags()函数。flags()函数有不带参数与带 参数两 种形式:ling ios ::flags(); 用于返回当前的状态 标志字; ling ios ::flags (liog flag); 返回当前的状态 标志字后,再者将状态标志字设置成flag(参数)。 flags(liog flag)函数与setf(liog flags)函数的差别在于:setf()函数是在原有的基础上追加设定的,而flags()函数是用 新设定覆盖以前的状态标志字。 例 7.2几个成员函数的使用 方法 #include <iostream.h> void showflags(long f) //输出状态标志字函数 { long i; for(i=0x8000;i;i=i>>1)//用右移方法使i中的值为”1”的位不断右移 if (i&f) cout<<”1”; //判断f中的某一位是否为”1” else cout <<”0”; cout<<endl; }

  12. 11 接1 例 7.2 void main() { long f; 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); //显示设置后的状态标志字 } 程序运行结果为;0010000000000001 (1)0010110000000001 (2) 0010010000000001 (3)0000000000100000 (4)0000000000100000 (5)

  13. 12 (4)设置域宽 域宽主要用来控制输出,在ios 类中域 宽存放在数据成员int x_width中,设置域宽的成员函数有两个,其一般格式为:int ios ::width(); 返回当的域宽值 int ios ::width(int w); 设置域宽,并返回原来的域 宽 (5)设置输出的精度 精度用来控制浮点数的输出显示精度,在ios类中用数据成员int x_precision来存放精度,设置精度的成员函数的一般格式为: int ios::precision(int p); 重新设置浮点数所需小数的位数,并返回设置前的位数 (6)填充字符 填充字符的作用是:当输出值不满域宽时用填充字符来填充,缺省情况下填充字符为空格,所以在使用填充字符函数时,必须与width()函数相配合,否则就没有意义,在ios类中用数据成员x_fill来存放填充字符。填充字符的成员函数有两个,其一般形式为: char ios ::fill(); 返回当的填充字符 char ios ::fill(char ch); 用ch重新设置填充字符,并返回设置前的填充字符。

  14. 13 例 7.3 #include <iostream.h> void main() { 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”;

  15. 14 程序运行结果如下:x_width=0x_fill=x_precision=0123 123.45678------------------------------------- ****x_width=10,x_fill= ,x_preciosion=4**** 123 123.4568 234.567x_width=0x_fill=x_precision=4------------------------------------- ****x_width=10,x_fill=&,x_precision=4**** &&&&&&&123 123.4568123&&&&&&& 123.4568x_width=0x_fill=&x_precision=4 接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; }

  16. 这程序建立了如下的表x sqrt(x) x^2 1 1 1 2 1.4142 4 3 1.7321 9 4 2 16 5 2.2361 25 6 2.4495 36 7 2.6458 49 8 2.8284 64 9 3 8110 3.1623 100 11 3.3166 12112 3.4641 14413 3.6056 16914 3.7417 19615 3.873 22516 4 25617 4.1231 28918 4.2426 32419 4.3598 36120 4.4721 400 15 例7.4 利用控制输入输出格式的成员函数建立对齐的数字表 #include<iostream..h> #include<math.h> void main() { double x; cout,precision(4); cout<<” x sqrt(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’; } }

  17. 16 7.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( int n )把转换基数设置为n(n的值为0,8,10,或16),n的缺省值为”0”,即以十进制形式输出。

  18. 17 ( 9 ) resetiosflags (long f ) 关闭由参数 f 指定的格式标志,可用于输入或输出。 ( 10 ) setiosflags (long f ) 设置由参数 f 指定的格式标志,可用于输入或输出。 ( 11 ) setfill (int c ) c 为填充字符,缺省时为空格,可用于输入或输出。 ( 12 ) setprecision (int n )设置数据小数部分的位数,缺省时小数的位数为6,可用输入输出。 ( 13 ) setw (int n) 设置域宽为n,可用于输入或输出。

  19. 18 操纵符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 文件中定义。

  20. 19 例7. 5 使用操纵符的输入输出格式控制 #include <iostream.h> #include <iomanip.h> void main ( ) { cout <<setw (10)<<12<<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::scientific)<<setfill(‘#’)<<setw(8)<<123<<endl; // ⑦ cout<<resetiosflags(ios::scientific)<<setfill(‘$’)<<setw(8)<<456<<endl; // ⑧ } • 程序运行结果为: • 1234567 ① • 123 1.234567e+02 ② • 123 7b ③ • 7b 173 ④ • 173 123 ⑤ • 123.4568 ⑥ • 123##### ⑦ • $$$$$456 ⑧

  21. 20 例7.6 二次方表与二次方根表的程序的程序的另一个版本 #include<iostream.h> #include<iomanip.h> #include<math.h> void main ( ) { double x; cout<<setprecision (4); cout << “ x sqrt (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’; } }

  22. 21 3. 用户自定义的操纵符 C++除了提供此同预定义的操纵符外,也允许用户自定义操纵符,把程序中频繁使用的输入输出操作合并成一个操纵符。 若为输出流定义操纵符函数,则定义形式如下: ostream &manip_name(ostream &stream) { //自定义代码 return stream; } 若为输出流定义操纵符函数,则定义形式如下: istream &manip_name(istream &stream) { //自定义代码 return stream; }

  23. 22 例 7.7 自定义的操纵符 #include <iostream.h> #include<iomanip.h> ostream &output 1(ostream &stream) { stream.setf(ios::left); stream<<setw(10)<<hex<<setfill(‘&’); return stream; } void main( ) { cout<<123<<endl; cout<<output 1<<123<<endl; } 程序运行结果如下: 123 7b&&&&&&&&

  24. 23 例 7.8 #include<iostream.h> #include<iomanip.h> istream &inputl (istream &in) { cin>>hex; cout<< “Enter number using hex format:”; return in; } void main ( ) { int i; cin>>inputl>>i; cout <<endl; } 以上程序中定义了一个操纵符函数input1,该函数要求输入一个十六进制数。 程序运行后,屏幕上显示: Enter number using hex format: 提示用户输入一个十六进制数。

  25. 24 7.4用户自定义类型的输入输出 用户自定义的类型数据的输入或输出,可以通过重载运算符 “>>”和 “<<”来实现,使“>>”和 “<<”可以直接用来输入或输出类的对象。 7.4.1 重载输出运算符 “<<” 定义输出运算符”<<”重载函数的一般格式如下: ostream &operator <<(ostream &stream, class_name obj ) { //操作代码 return stream; } 函数中的一个参数是对ostream 对象的引用,它可以是其它任何合法的标示符,但必须与return后面的标示符相同。第二个参数接受将被输出的对象,其中class_name是类名,obj为该类的对象名。

  26. 25 例 7.9输出运算符 “<<”重载的例子 #include <iostream.h> class coord{ public: int x,y; coord ( ) {x=0; y=0;} coord ( int I,int j) {x=I; y=j;} }; ostream &operator <<(ostream &stream, coord ob) { stream <<ob.x<< “,”<<ob.y<<endl; return stream; } void main ( ) { coord a ( 5,6),b (10,34); cout <<a<<b; } 程序运行结果如下: 5,6 10,34

  27. 26 例 7.10 把重载输出运算符定义为类的友元函数,这样就可以访问类的私有成员 #include <iostream.h> class coord{ int x,y; public: coord ( ) {x=0; y=0;} coord ( int i,int j) {x=i; y=j;} friend ostream &operator<<(ostream &stream, coord ob); }; ostream &operator<<(ostream &stream, coord ob) { stream<<ob.x <<”,”<<ob.y<<endl; return stream; } void main ( ) { coord a ( 5,6),b (10,34); cout <<a<<b; } 程序运行结果如下: 5,6 10,34

  28. 27 7.4.2 重载输入运算符 “>>” 只是要把ostream换成istream ,把”<<”用”>>”代替,第二个参数是一个引用。 定义输入运算符”>>”重载函数的一般格式如下: istream &operator >>(istream &stream, class_name &obj ) { //操作代码 return stream; } 例 7.11重载输入运算符 “>>” #include<iostream.h> class three_d{ int x,y,z; public: three_d(int a, int b, int c) {x=a; y=b; z=c;} friend ostream &operator<<(ostream &output, three_d ob); friend istream &operator>>(istream &input, three_d &ob); };

  29. 28 接1 例 7.11 ostream &operator<<(ostream &output, three_d ob); { output<<ob.x<< “,”; output<<ob.y<< “,”; output<<ob.z<<endl; return output ; } istream &operator>>(istream &input, three_d &ob); { cout<<”Enter x,y,z value:”; input>>ob.x; input>>ob.y; input>>ob.z; return input; }

  30. 29 接2 例 7.11 程序运行结果如下: 10,20,30 Enter x,y,z value :40 50 60 40,50,60 void main ( ) { three_d obj (10,20,30); //定义类three_d的对象obj cout<<obj; //输出对象obj的成员值 cin>>obj; //输出对象obj的各成员值,将原值覆盖 cout<<obj; //输出对象obj的成员值(新值) }

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

  32. 31 建立流的过程就是定义流类的对象,例如: ifstream in; ofstream out; fstream both; 它们分别定义了输入流对象in,输出流对象out,输入输出流对象both。 Open( )函数是上述三个流类的成员函数,其原型为: void open(const unsigned char *,int mode , int access=filebuf::openprot); 打开语句: 流类的对象. open(const unsigned char *,int mode ,int access=filebuf::openprot); 其中第一个参数是用来传递文件名的;第二个参数mode的值决定文件将如何被打开,它必须取下面的值中的一个;access的值决定文件的访问方式。

  33. 32 ios::app 使输出追加到文件尾部 ios::ate 查找文件尾 ios::in 打开一个文件进行读操作 ios::nocreate 文件不存在时,导致open( )失败 ios::noreplace 若文件存在,则open( )失败 ios::out 打开一个文件进行写操作 ios::trunc 使同名文件被删除 ios::binary 文件以二进制方式打开,缺省时为文本文件 访问方式 0 普通文件 1 只读文件 2 隐含文件 4 系统文件 8 备份文件

  34. 33 打开文件的步骤: (1) 定义一个类的对象,例如: ofstream out; (2) 使用open( )函数打开文件。例如:out.open(”test”,ios::out ,0); 文件只有在打开后,才能对文件进行读写操作。由于某些原因,可能打开失败,因此使用文件之前必须进行执行检测,以确认打开一个文件是否成功。可以使用类似下面的方法进行检测: if(! mystream) { cout<<”cannot open file! \n”; //错误处理代码 } 在实际编程时,打开一个文件的最常见的形式为: ofstream out (”test”) ; 用 if (!out) 检测是否打开成功 它相当于语句: ofstream out; out.open(”test”); 2. 文件的关闭 关闭文件可使用close( )函数完成,close函数也是流类中的成员函数,它不带参数,没有返回值,例如: out.close ( );

  35. 34 7.5.2 文件的读写 在含有文件操作的程序中,必须有如下的预处理命令: # include <fstream.h> 1. 文本文件的读写 文件打开后,文本文件的读写使用运算符“<<”与“>>”,只是必须用与文件相连接的流代替cin和cout。 例 7.12 把一个整数、一个浮点数和一个字符串写到磁盘文件test中。 # include <fstream.h> int main () { ofstream fout(”test”); if (!fout) { cout<<”cannot open output file \n”; return 1; } fout<<10<<” ”<<123.456<<” \”This is a test file.\”\n”; fout.close(); return 0; }用“写字板”可以看到test文件的内容:10 123.456 “this is a test file”

  36. 35 例 7.13 先建立一个输出文件,向它写入数据,然后关闭文件,再按输入模式打开它,并读取信息。 # include <fstream.h> void main () { ofstream fout(”test2”); if(!fout) { cout<<”cannot open output file .\n”; return 1; } fout<<” Hello!\n”; fout<<100<<’ ’<<hex<<100<<endl; fout.close (); ifstream fin(”test2”); if(!fin) { cout<<”cannot open input file .\n”; return 1; } char str[80]; int I; fin>>str>>i; cout<<str<<” ”<<i<<endl; fin.close(); } 程序建立一个输出文件test2,并向它写入数据,关闭输出文件test2。再将文件test2按输入模式打开,并将字符串“hello!\n”读给字符数组str,将整数100读给整型变量i。最后在屏幕上显示出str和I的值,如下所示: Hello! 100

  37. 36 例 7.14 从键盘读入字符串,并将它们写进磁盘文件。当用户输入空白字符时,程序停止。 # include <fstream.h> # include <stdio.h> void main(int argc,char *argv[]) { if(argc!=2) { cout<<”Usage: write <filename>\n”; return 1; } ofstream outf (argv[1]); if (! outf) { cout<<”cannot open output file .\n”; return 1; } char str[60]; cout<<”Write strings to disk, RETURN to stop\n”; do { cout<<”:”; gets(str); outf<<str<<endl; }while (*str); outf.close (); } 这个例子采用了命令行参数的形式,输入以下命令行: <可执行文件名> <磁盘文件名> ↙ 程序运行情况如下: Write strings to disk,RETURN to stop :abcdefg (从键盘输入一个字符串) :↙ (输入空行,程序停止) 程序运行后,在磁盘上生成一个名为<磁盘文件名>的文件,其内容: abcdefg

  38. 37 2. 二进制文件的读写 任何文件,无论它包含格式化的文本还是包含原始数据,都能以文本方式或二进制方式打开。文本文件是字符流,而二进制文件是字节流。 (1) 用get( )函数和put( )函数读写二进制文件 get( )是输入流类istream中定义的成员函数,它可以从与流对象连接的文件中读出数据,每次读出一个字节(字符)。put( )是输出流类ostream中的成员函数,它可以向与流对象连接的文件中写入数据,每次写入一个字节(字符)。 get( )函数有许多格式,其最一般的使用版本的原型如下: istream &get(unsigned char &ch); get( )函数从相关流中只读一个字符,并把该值放如引用ch&中。 put( )函数的原型如下: ostream &put(char ch); put( )函数将字符ch写入流中。

  39. 38 例 7.15 实现任意类型的文件拷贝。 # include <iostream.h> # include <fstream.h> void main (int argc, char *argv[ ]) { char ch; if (argc!=3) { cout<<”Bad commond !\n”; return 0; } ifstream inf (argv[1]); if (! inf) { cout<<”Cannot open souce file.”; return 1; } ofstream outf (argv[2]); if (! outf) { cout<<”Cannot open target file.”; return 1; } while (inf) { inf.get (ch); outf.put (ch); } inf.close ( ); outf.close ( ); } 假定本程序的文件名为mvc7_15.cpp,经编译、连接后生成的可执行文件名为mvc7_15.exe,则在DOS下输入以下命令行: D> mvc7_15 file1.exe file2.exe 该程序的执行结果,是把文件file1.exe中的信息拷贝到文件file2.exe中

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

  41. 40 例 7.16在屏幕上显示任何给定文件的内容。 # include <iostream.h> # include <fstream.h> main (int argc, char *argv[ ]) { char ch; if (argc!=2) { cout<<”Usage: PR<filename>\n”; return 1; } ifstream in (argv[1]); if (! in) { cout<<”Cannot open file”; return 1; } while (! in.eof ( )) { in.get (ch); cout<<ch; } return 0; } 假定本程序的文件名为mvc7_16.cpp,经编译、连接后生成的可执行文件名为mvc7_16.exe,则在DOS下输入以下命令行: D> mvc7_16 file1 该程序的执行结果,是把文件 file1 中的信息在屏幕上显示。

  42. 41 (2) 用read( )函数和write( )函数读写二进制文件 有时需要读写一组数据 (如一个结构变量的值),为此C++提供了两个函数read( )和write( ),用来读写一个数据块。 ① read( )函数: 函数原型: istream &read (unsigned char *buf,int num); read( )是类istream中的成员函数,其功能为:从相应的流中读取num个字节(字符),并把它们放入指针buf所指的缓冲区中。 调用格式: read(缓冲区首址,读入的字节数); 注意:“缓冲区首址”的数据类型为unsigned char*,当输入其它类型数据时,必须进行类型转换,例如: int array[ ]={50,60,70};定义了一个整型数组array, read((unsigned char *)&array,sizeof(array); 对整型数组array,为了把数据从文件读入到它中,必须在read( )函数中把它转换为unsigned char *类型。由sizeof( )函数确定要读入的字节数。

  43. 42 ② write( )函数: 函数原型: ostream &write(const unsigned char *buf, int num); write( )是流类ostream的成员函数,利用该函数,可以把buf所指的缓冲区num个字节写到相应的流上。参数的含义及调用注意事项与read()函数类似。 注意:如果在num个字节被读出之前就达到了文件尾,则read( )只是停止执行,此时缓冲区包含这些字符。我们可以用另一个成员函数gcount( )统计出有多少字符被读出。gcount( )的原型如下: int gcount( );它返回所读取的字节数。

  44. 43 例 7.17 用write( )函数向文件test中写入双精度数与字符串。 # include <iostream.h> # include <fstream.h> # include <string.h> main( ) { ofstream outf(”test”); if (! out) { cout<<”cannot open output file .\n”; return 1; } double num=100.45; char str [ ]=”This is a test”; out.write ((char * )&num,sizeof (double )); out.write (str, strlen (str)); out.close ( ); return 0; } 程序执行后,屏幕上不显示任何信息,但程序已将双精度100.45和字符串“this is a test” 以二进制形式写入文件test中。用下面的程序 可以读取文件test中的数据,并在屏幕上显示出来,以验证前面的程序操作。

  45. 44 例 7.18 用read( ) 函数读取例7.17中程序所建立的文件。 # include <iostream.h> # include <fstream.h> # include <string.h> main() { ifstream in(”test”); if (! in) { cout<<”cannot open input file .\n”; return 1; } double num; char str [80]; in.read ((char * )&num, sizeof (double)); in.read (str, 14); cout<<num<<’ ’<<str; in.close ( ); return 0; } 程序运行结果为: 100.45 This is a test

  46. 45 3. 文件的随机读写 前面介绍的文件操作都是按一定顺序进行读写的,因此称为顺序文件。 C++在类istream及类ostream中定义了几个与在输出流中随机移动文件指针的成员函数,则可以在流内随机移动文件指针,从而可以对文件的任意数据进行随机读写。用函数seekg( )和seekp( )进行随机访问。函数seekg( )用于输入文件,函数seekp( )用于输出文件。

  47. 46 它们的函数原型如下: istream &seekg (streamoff offset, seek_dir origin); ostream &seekp (streamoff offset, seek_dir origin); 其中,参数origin表示文件指针的起始位置,offset表示相对于这个起始位置的位移量。seek_dir是一个系统定义的枚举名,origin是枚举变量。origin的取值有以下三种情况: ios::beg从文件头开始,把文件指针移动由offset指定的距离。offset的值为正数 ios::cur从当前位置开始,把文件指针向前(后)移动由offset指定的距离。 offset 的值为正或负数,正数时向前移,负数时向后移。 ios::end从文件尾开始,把文件指针移动由offset指定的距离,offset的值为负数进行文件的随机读写时,可以用以下函数测试文件指针的当前位置: streampos tellg( );用于输入文件。 streampos tellp( );用于输出文件。 streampos是在iostream.h中定义的类型,实际上是long型的。

  48. 例 7.19 演示seekp( )函数。它修改文件中的指定字符。执行时在命令行指定文件名,其后跟想修改的字符的位置,然后再跟新的字符。 47 # include <iostream.h> # include <fstream.h> # include <stdlib.h> int main (int argc, char *argv[ ]) { if (argc!=4) { cout<<”Usage: CHANGE<filename> <byte> <char>\n”; return 1; } fstream out (argv[1], ios::in|ios::out); if (! out) { cout<<”Cannot open file”<<argv[1]<<”\n”; return 1; } out.seekp (atoi (argv[2]), ios::beg); out.put ( *argv[3]); out.close ( ); return 0; } 假定上述程序的文件名为mvc7_19.cpp,经编译、连接生成的可执行文件名为mvc7_19.exe。需要修改的文件名为file,file的内容为: AAAAAAAAAA1234567890 执行下述命令: D> mvc7_19 file 5 # 程序运行结果为: AAAAA#AAAA1234567890

  49. 42 48 例 7.20 使用seekg( )函数,它从指定的位置开始显示文件内容。 # include <iostream.h> #include <fstream.h> # include <stdlib.h> void main (int argc, char * argv[ ]) { char ch; if (argc!=3 ) { cout<<”Usage: LOCATE<filename><loc>\n”; return 1; } ifstream inf (argv[1] ); if (! inf) { cout<<”Cannot open input file. \n”; return 1; } inf.seekg (atoi (argv[2]), ios::beg); while (! inf.eof ( )) { inf.get (ch); cout<<ch; } inf.close ( ); } 假定程序的执行文件文件名为mvc7_20.exe,要显示文件名为file,希望从第5个位置开始显示,则执行的命令行: D>mvc7_20 file 5 <cr> 程序运行结果为: #AAAA1234567890

  50. 49 7.6 应 用 举 例 例7.21 重载运算符“<<”和“>>”,使用户能直接输入和输出复数。 #include<iostream.h> class complex{ double real,imag; public: complex(double r, double i) { real=r; imag=i;} complex( ) { real=0; imag=0;} friend complex operator+(complex, complex); friend ostream &operator<<(ostream&, complex&); friend istream &operator>>(istream&, complex&); }; complex operator+(complex a, complex b)//定义重载运算符“+” { complex temp; temp.real=a.real+b.real; temp.imag=a.imag+b.imag; return temp; }

More Related