C的IO流库-首都师范大学.ppt

上传人:za****8 文档编号:14650010 上传时间:2020-07-27 格式:PPT 页数:149 大小:672KB
收藏 版权申诉 举报 下载
C的IO流库-首都师范大学.ppt_第1页
第1页 / 共149页
C的IO流库-首都师范大学.ppt_第2页
第2页 / 共149页
C的IO流库-首都师范大学.ppt_第3页
第3页 / 共149页
资源描述:

《C的IO流库-首都师范大学.ppt》由会员分享,可在线阅读,更多相关《C的IO流库-首都师范大学.ppt(149页珍藏版)》请在装配图网上搜索。

1、第八章 C+ 的 I/O 流库,C+ 为什麽要建立自己的输入输出系统? 1 C 虽然具有一个灵活和功能强大的输入输出系统, 但它并不支持自定义类型。例如: class account char name30; double balance; public: account(); account(char*, double); ;, account acnt; scanf(“%account”, / 错误,不支持 account 类型 因为输入函数 scanf 和输出函数 printf 的格式串形参 只能与系统预定义类型匹配,而无法识别用户的自 定义类型,并且也不能通过重载定义 scanf 和

2、printf 函数的新版本,使它们的格式串形参能匹配任意用 户自定义类型。,2 面向对象程序设计必须定义众多的用户自定义类, 如何以面向对象的设计原则和方法为自定义类设计 既规格统一,又适应个性化的输入输出操作行为是 十分必要的。因此 C+ 必须建立一个能通过对输入 输出操作重载的方法实现对任意自定义类型对象输 入输出支持的系统。,本章要点 1 C+ 流库结构 流库的概念、流库的组成。 2 标准输入输出流 输入输出流类的定义、输入输出运算符、输入输出 的格式控制。 3 自定义类的输入输出 输入输出运算符的重载。 4 文件的输入输出流 文件的打开、关闭和读写。 5使用 MFC 的对话框类实现输入

3、输出,8.1 C+ 流库结构 8.1.1 流库的概念 流(stream)是从源(数据的生产者)到目标(数 据的使用者)被传输数据的引用。每个流都是一个与 某种数据传输设备相关联的对象。 流具有方向性: 输入流是与输入设备(如键盘)关联的流。 输出流是与输出设备(如显示器屏幕)关联的流。 输入输出流是与输入输出设备(如磁盘)关联的流。,C+ 中包含的预定义流: cin 输入流,与输入设备关联。 cout 输出流,与输出设备关联。 cerr 非缓冲型错误信息流,与错误输出设备关联; clog 缓冲型错误信息流,与错误输出设备关联。 在缺省情况下,指定的输入设备是控制台键盘,输 出设备是控制台显示器

4、终端。在任何情况下,指定的 错误输出设备总是控制台显示器终端。,cin 和 cout 的使用方法我们已经很熟悉了。cerr 和 clog 均是用来输出错误信息,它们的使用方法与 cout 基本相同,只不过它们所关联的设备始终是控制台显 示器,而不随着 cout 关联设备的改变而变化。cerr 和 clog 之间的区别是: cerr 对输出的错误信息不缓冲,因而发送给它的任何内 容都立即输出。 clog 输出的错误信息被缓冲,当缓冲区满时才进行输 出,也可以通过刷新流的方式(遇到操纵符 endl 或 flush)强迫刷新缓冲区导致显示输出。,下面给出一段使用预定义输入输出流信息的程序: cout

5、 sales; cout num; if (num = 0) cerr The average can not be computed.n; else avgsales = sales / num; cout The average selling price per nuit was ; cout avgsales n; ,C+ 流库是用面向对象的设计方法建立起来的输入 输出类库,它具有两个平行的根基类 streambuf 和 ios, 库中所有其他的类均从它们直接或间接派生。系统中 预定义流,cin、cout、cerr、clog 都是流库中相应类的 对象。,8.1.2 streambuf

6、类 streambuf 类是流库的根基类,它为输入输出物理设 备提供缓冲区和流处理的一些通用方法。 C+ 将输入输出流均视为字节流,因此缓冲区是由 一个字符串和两个指针组成的。这两个指针分别指 向数据流在输入缓冲区中的插入位置和在输出缓冲 区的提取位置。 streambuf 类提供对缓冲区的底层操作,例如设置缓 冲区、对缓冲区指针进行操作、从缓冲区取字节、向 缓冲区存储字节等。streambuf 类有三个派生类,filebuf 类、strstreambuf 类和 conbuf 类。它们的派生层次关系 如图所示:, filebuf 类扩展了 streambuf 类的功能,用于文件流与 文件缓冲区

7、相关联,实现对文件缓冲区中的字节序 列的读写操作: 写文件:缓冲区内容按字节写到指定的文件中, 然后刷新缓冲区。 读文件:指定文件内容按字节读到缓冲区中。 打开文件:filebuf 与被读或写的文件相关联。,streambuf, 关闭文件:filebuf 与被读或写的文件解除关联。 strstreambuf 类扩展了 streambuf 类的功能,提供了将 内存作为输入输出设备时,进行提取和插入操作的 缓冲区管理。 conbuf 类扩展了 streambuf 类的功能,用于控制台显 示器输出缓冲区关联和管理,提供光标控制、颜色 设置、活动窗口定义、清屏、行清除等屏幕控制功 能(注意,这些屏幕控

8、制功能在有些编译器版本中 不提供,例如 visual C+)。 通常情况下,对设备缓冲区的操作一般使用上述三 个派生类,很少直接使用基类 streambuf。,8.1.3 ios 类 ios 类及其派生类为用户提供使用流的接口,该类具 有一个 streambuf 类型指针指向流的缓冲区。ios 类及其 派生类对象通过该指针使用 streambuf 及其派生类对象 完成输入输出时的格式化或非格式化转换,并检查输 入输出的错误。ios 是流库中的另一个根基类,它有四 个直接派生类: 输入流类 istream: class istream : virtual public ios; 输出流类 ost

9、ream: class ostream : virtual public ios;, 文件流类 fstreambase: class fstreambase : virtual public ios; 字符串流类 strstreambase: class strstreambase : virtual public ios; 这四个派生类成为流类库中的基本流类,它们又组 合派生出以下的流类: 输入文件流类 ifstream: class ifstream : public istream, public fstreambase; 输入字符串流类 istrstream: class istrst

10、ream : public istream, public strstreambase; 输出文件流类 ofstream: class ofstream : public ostream, public fstreambase;, 输出字符串流类 ostrstream: class ostrstream : public ostream, public strstreambase; 控制台输出流类 constream: class constream : public ostream; 输入输出流类 iostream: class iostream : public istream, publ

11、ic ostream; 输入输出文件流类 fstream: class fstream : public iostream, public fstreambase; 输入输出字符串流类 strstream: class strstream : public iostream, public strstreambase;,从上述的 istream、ostream 和 iostream 又分别派生出 具有赋值运算符“=”重载的新类: 带赋值的输入流类 istream_withassign: class istream_withassign : public istream; 带赋值的输出流类 os

12、tream_withassign: class ostream_withassign : public ostream; 带赋值的输入输出流类 iostream_withassign: class iostream_withassign : public iostream; 上述流类的派生层次结构如下图所示。,ios,系统预定义流 cin、cout、cerr 和 clog 在系统头文件 iostream.h 中被定义: extern _CRTIMP istream_withassign cin; extern ostream_withassign _CRTIMP cout; extern os

13、tream_withassign _CRTIMP cerr; extern ostream_withassign _CRTIMP clog; 显然,用户也可以用 istream 和 ostream 等流类定义 自己的流对象,例如:istream is;ostream os; 对预定义类型数据的输入输出操作已经定义为流类 的操作,而对用户自定义类型对象的输入输出操作则 可以通过重载运算符 “”和“” 得以实现。,Java 的 I/O 流类在构造和使用上与 C+ 有一些有趣 的差别: 1 C+ 的 I/O 流类库是把所有的输入输出功能封装在 数量相对较少的几个流类中,自定义类则是通过重 载机制使得

14、流类对象能够对自定义类对象进行输入 输出操作。 而 Java 则几乎为每一种情况提供了一个独立的类。 例如,底层的字节流操作类、按数据类型划分的各 种高级操作类,对底层 I/O 包装后进行某种特定操 作(如 Unicode 读写)的类,随机读写操作类,数 组读写类等等。,2 C+ 的流在缺省情况下是进行缓冲的,但 Java 的流 在缺省情况下是不缓冲的。但可以调用提供了缓冲 功能的类对一个 Java 的流进行缓冲。 3 在 Java 中,所有的整数和浮点数都是以大端字节顺 序进行输入输出的,与底层平台无关。这与 C+ 中 的情况不同,因此 Java 所产生的数据文件的可移植 性更高。,4 在典

15、型的 C+ 程序中,字符均使用 ASCII 编码形式 表示(无论是单独使用的字符还是字符串中的字 符)。这与字符从输入设备读入或写到输出设备都 保持 ASCII 编码形式是一致的。 一个典型的 Java 程序中,字符始终是用两个字节的 Unicode 形式表示的。当从输入设备读入 ASCII 编码 形式的字符时,必须先转换为 Unicode 形式后再写 入内存;当将 Unicode 形式字符写到输出设备时, 必须先转换为 ASCII 编码形式后再写入输出设备。 Java 的流类的层次结构如下图所示:,OutputStream,InputStream,返回,Writer,Reader,8.2 标

16、准输入输出流 8.2.1 输入输出流类定义 istream 类和 ostream 类在流库中分别提供基本的标 准输入输出操作,是使用流库的主要接口,在系统头 文件 iostream.h 中,它们的类定义分别如下: class istream:virtual public ios public: istream(streambuf*);/构造函数 / 从输入流中将字符读取到给定指针 char* 指向的内存,直 / 至遇到分界符、文件结束符或读至(len-1)个字符为止。 istream,/ 从输入流读取字符到给定的 streambuf,直至遇到分界符。 istream,/ 从读入流读取给定数目的

17、字符到 char* 指向的内存空间。 / 如果发生错误时,getcount 函数可得到实际读入的数目。 istream,/ 按给定偏移 streamoff ( typedef long streamoff)移动输入 / 文件指针,指示偏移方向的枚举值 ios:seek_dir 的取值: / beg = 从文件开始;cur = 从当前位置;end = 从文件尾。 istream /对系统所有的预定义类型都给出了的重载定义。 ;,class ostream:virtual public ios public: ostream(streambuf*);/ 构造函数 ostream,streampos

18、 tellp(); / 返回输出流中当前指针位置。 / 可重载的输出运算符 ostream,8.2.2 输入输出运算符的使用 8.2.3 格式控制的输入输出 输入输出的格式控制可以使得人机交互界面更加友 好、美观。在 C 程序中,输入输出是使用 C 运行库的 scanf 和 printf 函数完成的,输入输出的格式是通过这两 个函数的格式描述串参数控制的。在 C+ 程序中,虽 仍然可以使用 scanf 和 printf 函数,但在面向对象的程 序设计中,输入输出是使用流类库中的输入输出流完 成的,因此输入输出的格式控制必须使用流类库提供 的格式控制的方法: 使用 ios 类的格式控制成员函数;

19、 使用被称为格式操纵符的特殊函数。,1 用 ios 类成员函数进行输入输出格式化 ios 类提供了用于输入输出格式控制的成员函数。 这些函数进行格式控制的方法是修改以下属性: 格式标志属性 x_flags:标志的不同状态值指定输 入输出数据的不同格式(如对齐规则、数值转换 基、数字表示规则等)。 输出域宽属性 x_width: 指定输出数据所占显示 区域的宽度。 填充字符属性 x_fill:指定输出显示域中数据为占 空间的填充字符; 输出精度属性 x_precision:指定浮点数输出的小 数部分显示位数。, 格式标志 C+ 中每个流对象的输入输出格式都是依据指定 格式进行的,也就是说,流对象

20、的每次输入“” 操作是按照当前格式标志 x_flags 中 的格式状态完成的。该属性是一个 protected 成 员,在类外访问该属性是通过公有的格式控制成 员函数实现的。注意,该属性可以在 ios 的派生 类内被访问。为了便于提供格式控制成员函数的 参数和参数具有良好的可读性,ios 类定义了一 个公有的无名枚举数据成员,用户可以使用这些 特定的枚举元素,形成所需要的格式状态传递给 相应的格式控制成员函数。,class _CRTIMP ios public: enum skipws = 0 x0001, / 跳过输入中的空白,用于输入 left = 0 x0002, / 左对齐输出,用于输

21、出 right = 0 x0004, / 右对齐输出,用于输出 internal = 0 x0008, / 符号或基数指示符与数字之间添加填充符,用于输出 dec = 0 x0010, / 基数为 10 进制,用于输入输出 oct = 0 x0020, / 基数为 8 进制,用于输入输出 hex = 0 x0040, / 基数为 16 进制,用于输入输出,showbase = 0 x0080, / 显示基数指示符,用于输出 showpoint = 0 x0100, / 显示小数点,用于输出 uppercase = 0 x0200, / 16 进制输出时,数基指示符和 / 数值中的字母一律为大写

22、,用于输出 showpos = 0 x0400, / 正数前显示+符号,用于输出 scientific = 0 x0800, / 科学表示法浮点数,用于输出 fixed = 0 x1000, / 定点形式显示浮点数,用于输出 unitbuf = 0 x2000, /输出后立即刷新流,用于输出。 stdio = 0 x4000, / 刷新 stdout 和 stderr,用于输出。 ; inline long flags() const;/ 返回当前格式标志。,inline long flags(long _l); / 设置指定格式 _l,返回原有格式。 inline long setf(lon

23、g _f, long _m); / 依据掩码 _m 设置指定格式 _f,返回原有格式。inline long unsetf(long _l); / 清除指定格式 _l,并返回原有标志。 inline int width() const;/ 返回当前域宽值。 inline int width(int _i); / 设置指定域宽 _i,并返回原有域宽值。 inline ostream* tie(ostream* _os); / 将流连接到_os 指向输出流,并返回原来的流指针。 inline ostream* tie() const;/ 返回原来的流指针。,inline fill() const;

24、/ 返回当前填充字符。 inline char fill(char _c); / 设置指定填充字符,并返回原有填充字符。 inline int precision(int _i); / 设置指定浮点数精度,并返回原有浮点数精度。 inline int precision() const;/ 返回当前的浮点数精度。 inline int rdstate() const;/ 返回当前的错误状态。 inline void clear(int _i = 0); / 根据掩码 _i 设置或清除错误状态位。 protected: ,long x_flags; int x_precision; char x

25、_fill; int x_width; ;,格式枚举元素值有一个共同的特点,即使用不同 位为 1 二进制数表示不同的格式值,也就是说, 枚举元素值的二进制表示只有一位为 1。例如: skipws0 x0001: 0000 0000 0000 0001 left0 x0002: 0000 0000 0000 0010 right0 x0004: 0000 0000 0000 0100 显然,所需要的特定格式标志将可以是一个枚举 元素值或几个的枚举元素进行或运算组合而成, 例如,欲设置左对齐 10 进制科学表示法显示浮 点数的输出格式,则格式标志可以通过 ios:left | ios:dec |

26、ios:scientific 得到,16 进制值为 0 x0812,10 进制值为 2066。, 用成员函数对格式标志进行操作 置格式标志 所谓设置格式标志是将格式属性 x_flags 的某 一位置1,使该位所对应的格式标志有效。设 置格式标志的成员函数是 setf,调用该成员函 数的一般形式为: 流对象.setf (ios:格式标志值); 例如: istream isobj; ostream osobj; isobj.setf(ios:skipws); osobj.setf(ios:left);,注意: isobj 和 osobj 为 istream 和 ostream 的用户定 义对象。在

27、编程中使用最多的是通过系统预 定义流对象设置格式,例如: cin.setf(ios:skipws); cout.setf(ios:left); 所设置的格式标志不改变格式属性 x_flags 的 原有的有效位,即在原有基础上追加设置。 例如,原来的状态标志字为: 0 x0011: 0000 0000 0001 0001 执行 cout.setf(ios:left) 后, x_flags 的值变为: 0 x0013: 0000 0000 0001 0011,例如: #include main() cout.setf(ios:showpos | ios:scientific); cout 567

28、567.89 endl; 程序执行结果: +567 +5.6789e02, 清除格式标志 与设置格式标志操作相反,是将格式属性 x_flags 的某一位清 0,使该位所对应的格式特 性失效。清除格式的成员函数是 unsetf,调用 该成员函数的一般形式为: 流对象.unsetf(ios:格式标志值); 注意:与设置格式标志相似,所清除的格式标 志只是使保存在 x_flags 中的当前格式属性的 相应位失效,而不改变格式属性其余的有效 位。例如,原格式属性为:,0 x0013: 0000 0000 0001 0011 执行 cout.unsetf(ios:left) 后,x_flags 的值变为

29、: 0 x0011: 0000 0000 0001 0001, 取状态属性 取出保存在 x_flags 中的格式属性。完成这一 操作的成员函数 flags,该函数有两个重载版 本,调用它们的格式有两种: long flags(); long flags(long flags); 前一种形式用于返回当前格式属性;后一种是 不仅将当前格式属性返回,并且将格式属性设 置为指定值 flags。 注意,带有参数的成员函数 flags 与成员函数 setf 不同,它对格式属性的修改是覆盖原值, 而不是在原值的基础上追加设置。例如:,#include void showflags(long f)/ 显示二进

30、制形式的状态字 long i; for (i = 0 x8000; i; i = i 1) if (i ,main() long f = cout.flags();showflags(f); cout.setf(ios:showpos | ios:scientific); f = cout.flags(); showflags(f); cout.unsetf(ios:scientific); f = cout.flags(); showflags(f); f = cout.flags(ios:oct);showflags(f); f = cout.flags(); showflags(f);

31、return 1; ,程序执行结果: 0000000000000000 0000110000000000 0000010000000000 0000010000000000 0000000000100000 分析程序的执行结果,可以清楚地看到格式属 性值的变化情况。, 设置域宽 域宽主要用来控制一个数据输出时所占显示区 域的宽度,在 ios 类中,域宽存放在保护类数 据成员 x_width 中。设置域宽的成员函数有两 个,调用它们的一般形式为: 流对象.width(); 流对象.width(域宽值); 第一种形式只用来返回当前的域宽值,后者用 来设置指定域宽,并返回原来的域宽值。, 设置显示的

32、精度 在 ios 类中,控制浮点数显示精度位数是被保 存在保护类数据成员 x_precision 中的。设置显 示精度的成员函数有两个,调用它们的一般形 式为: 流对象.precision(); 流对象.precision(精度位数); 第一种形式只用来返回当前的显示精度,后者 用来重新设置显示精度,并返回原来的显示精 度。, 设置填充字符 填充字符的作用是:当输出数据的长度小于显 示域宽时,用填充字符来填充显示域宽中数据 未占满的空间。缺省情况下填充字符为空格。 如果输出数据的长度大于域宽时,则填充字符 是没有意义的。因此,在使用填充字符时,必 须考虑与 width 函数相配合。在 ios

33、类中,填 充字符被保存在保护类数据成员 x_fill 中的。 设置填充字符的成员函数有两个,调用它们的 一般形式为:,流对象.fill(); 流对象.fill(填充字符); 第一种形式用来返回当前的填充字符,后者用 来重新设置填充字符,并返回原有的填充字 符。例如:,#include 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

34、_width = 10, x_fill = , x_precision = 8 *n; cout.width(10); cout.precision(8); 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 = ,cout x_fill = cout.fill() endl; cout x_p

35、recision = cout.precision() endl; return 1; 程序执行结果: x_width = 0 x_fill = x_precision = 6 123 123.457 -,* x_width = 10, x_fill = , x_precision = 8 * 123 123.45678 234.567 x_width = 0 x_fill = x_precision = 8 - * x_width = 10, x_fill = cout 123 setiosflags(ios:scientific) setw(20) 123.456789 endl; cou

36、t 123 setw(10) hex 123 endl; cout 123 setw(10) oct 123 endl; cout 123 setw(10) dec 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( 程序执行结果: 123567 123 1.234568e+002 123 7b 7b 17

37、3 173 123 123.5 123# cin input i; cout i output i endl; return 1; 程序执行结果: Enter number using hex format: a78e 42894 A78E返回,8.3 自定义类型的输入输出 从前面对 C+ 流类库的分析不难看出,系统预定义 类型数据的输入输出主要是通过使用输入运算符 (又称为流的提取运算符)和输出运算符 和输出运算符 是无法预先定义的。但却 为用户提供了使用运算符重载为自定义类型对象定义 输入输出操作的面向对象方法。解决自定义类型对象 输入输出操作的思路和方法有三种:,1 用户自定义类型总可以

38、分解成按指定结构组织起来 的预定义类型,对这组预定义类型数据当然可以使 用 或 运算符。使用这种方法的缺点: 在类外访问被分解得到的预定义类型数据必须通 过接口,必然降低访问效率。如果类数据成员均 定义为公有访问属性,虽然能提高访问效率,但 破坏了面向对象的数据隐藏原则。显然不能兼顾 访问效率和数据安全。 无法利用代码的重用性,增加了程序冗余度; 程序的可读性差;,2 在方法 1 的基础上建立用户自定义类的特定输入输 出成员函数。采用这种方法虽然解决了采用方法 1 的缺点,但仍然存在以下缺点: 增加了需要记忆的特定的输入输出成员函数名, 并在调用这些函数时,需在函数名前加缀对象 名,因此增加了

39、编程的复杂性。 这些函数只能单独使用(写成一个单独语句), 而不能放在输入或输出连续表达式中,无法统一 输入输出操作的形式。 3 采用重载 和 运算符的方法,并将运算符 函数定义成被输入或输出对象类的友元函数。这种 方法将会消除前两种方法所带来的缺点,是一种遵 循面向对象设计原则的方法。,8.3.1 重载输入运算符 输入运算符 是输入流类(将在第八章中详细讲 述)的成员函数。该运算符也是一个双目运算符,它 的左操作数必须是输入流类对象的引用,表示被输入 的信息必须来自标准的输入流设备;而右操作数是接 收输入信息的指定类对象的引用。因此,为自定义类 重载的输入运算符函数只能是类成员函数。,1 原

40、型 friend 输入流类,2 定义 输入流 ,3 调用 cin 类对象名; 例如: point pt; cin pt;,注意: 输入运算符重载函数的第一个参数的类型必须是输 入流类 istream 对象的引用,形参名(流对象名)可 以使用任何合法的标识符。 输入运算符重载函数的第二个参数的类型必须是接 收输入信息的指定类对象的引用,例如 point cout pt;,注意: 输出运算符重载函数的第一个参数的类型必须是输 出流类 ostream 对象的引用,形参名(流对象名)可 以使用任何合法的标识符。 输出运算符重载函数的第二个参数的类型必须是输 出信息的指定类对象或对象的引用,例如 poi

41、nt/ 输入流对象 ofstream out;/ 输出流对象 fstream io;/ 输入输出流对象,使用文件流类的成员函数 open 打开文件,也就是 使某一个文件与指定流相关联。open 的原型: void open( const char* szName, int mode, int nProt = filebuf:openprot ); 其中三个参数分别为: 1 文件名:字符串常量 szName 用来传递文件名。 2 打开方式:整型值 mode 指定了文件被打开的方 式,其取值范围如下表所示:,在 ios 类定义中 mode 值被定义为以下枚举: enum open_mode in

42、= 0 x01, out = 0 x02, ate = 0 x04, app = 0 x08, trunc = 0 x10, nocreate = 0 x20, noreplace = 0 x40, binary = 0 x80 ;,各个枚举值所指定的打开方式的详细含义: 追加方式 ios:app: The function performs a seek to the end of file. When new bytes are written to the file, they are always appended to the end, even if the position is

43、 moved with the ostream:seekp function. 查询文件尾方式 ios:ate: The function performs a seek to the end of file. When the first new byte is written to the file, it is appended to the end, but when subsequent bytes are written, they are written to the current position., 输入方式 ios:in: The file is opened for i

44、nput. The original file(if it exists) will not be truncated. 输出方式 ios:out: The file is opened for output. 更新方式 ios:trunc: If the file already exists, its contents are discarded. This mode is implied if ios:out is specified, and ios:ate, ios:app, and ios:in are not specified., 禁创建方式 ios:nocreate:VC+

45、2005 无此方式 If the file does not already exist, the function fails. 禁替换方式 ios:noreplace:VC+ 2005 无此方式 If the file already exists, the function fails. 二进制方式 ios:binary: Opens the file in binary mode (the default is text mode). Note that there is no ios:in or ios:out default mode for fstream objects. Yo

46、u must specify both modes if your fstream object must both read and write files.,3 访问保护方式:整数值 nProt 指定了被打开文件的 访问保护方式(文件的访问类型)。从函数原型 中可以知道 nProt 的缺省值是 filebuf:openprot,该 值对于 UNIX 操作系统是 0 x644,即普通文件。在 DOS 或 Windows 操作系统中, nProt 的值通常对 应文件属性,它们是: 0普通文件 1只读文件 2隐含文件 4系统文件 8备份文件,4 调用实例 打开一个输出文件 ofstream ou

47、t; out.open(test, ios:out, 0); 按普通文件访问打开一个输出文件 “test”,与输 出文件流 out 相关联。由于普通文件访问方式 和输出方式都是输出文件流的缺省创建方式, 因此,调用 open 函数的形式可简化为: out.open(test);, 打开一个输入输出文件 fstream both; both.open(test, ios:in | ios:out, 0); 由于文件流都提供具有打开文件功能的构造函数 (文件名、打开和访问方式均可作为参数),所 以创建文件流对象和打开文件用可以一步完成: ofstream out(test); fstream bo

48、th(test, ios:in | ios:out, 0); 注意,文件打开操作是否成功应调用成员函数 fail 进行检查,避免对无效文件读写所引起的系统错误。,fstream both; both.open(test, ios:in | ios:out, 0); if (both.fail() cout Cannot open file! n; 错误处理语句 文件使用完毕后,应该关闭文件,并与所关联的文 件流 “分离”。关闭文件使用文件流的成员函数 close()。 例如: both.close();,8.4.2 文件的读写 1 文本文件的读写 一旦文件被成功打开,文件中的文本数据信息的读

49、写操作与控制台文件信息的输入输出操作是完全一 致的。从流类库的定义说明中我们知道可以用于文 本数据输入和输出的运算符 和 是分别在 输入流类 istream 和输出流类 ostream 中定义的,而 用于文件读写的流类 ifstream、ofstream 和 fstream 是 istream 和 ostream 的派生类,它们之间的层次关系 如下:,显然, 和 也是 ifstream,ofstream 和 fstream 的运算符,但调用时,必须用 ifstream,ofstream 或 fstream 流类对象替代控制台文本信息输入输出使用 的输入流类对象(例如,cin)和输出流类对象(例

50、 如,cout )。,istream,ostream,fstreambase,例8-5 把一个整数、一个浮点数和一个字符串以文本 形式写入一个磁盘文件 test 中。显然,该程序执 行后,屏幕上是不会显示任何与程序有关的信息 的。而程序产生的磁盘文件可以使用 DOS 系统 的 type 命令或使用 Windows 平台的 “记事本” 或 其他可以读写纯文本文件的工具查看。文件“test” 中记录的信息为: 10 123.456 This is a text file.,例8-6 先建立一个输出文件 “test2”,向它写入数据, 然后关闭文件,再按输入模式打开 “test2” ,并 读取和显示

51、文件中的信息。 语句 fout 100 hex 100 endl; 使第二 个10进制 100 转换为16进制表示的文本串写入文 件 test2。使用 debug 程序可以看到文件中两个数 据文本存储格式: 48 65 6C 6C 6F 21 20 0D-0A 31 30 30 20 36 34 0D Hello!.100 64. 0A ., 按程序中的语句 fin str i j; 读入数据后,j 中保存的不是10 进制 100,而是10 进制 64。如 果要使 j = 100,则需要将上述语句改为: fin str i hex j; 此时,程序执行结果为: Hello! 100 100,例

52、8-7 从键盘读入字符串、并将它们写入磁盘。当用 户输入空白字符时,程序停止。 问题分析: 本程序采用了命令行参数的形式,执行程序时, 命令行中除程序的执行文件名外,还需要传递一 个参数,即输出文件名。因此命令行参数计数 argc = 2, 执行文件名保存在 argv0 中,而输出文 件名被存放在 argv1 中。例如,输出文件名为 file,则命令行应该是:write file 程序执行时,首先在屏幕上显示用户输入提示。 用户从键盘输入字符串,并写入命令行指定的输 出文件中,直至输入 CTRL-Z,即 ASCII 码 0 输入停止,文件关闭,程序执行结束。,2 二进制文件的读写 任何文件中无

53、论包含是文本数据还是二进制数据, 都能以文本方式或二进制方式打开。这就是说,文 件的打开方式并不能保证文件数据的形式和含义, 而确保文件数据的形式和含义关键是如何对文件的 数据进行读写。二进制文件中的数据是直接将数据 在内存中存放的形式映像到文件中,因此在读写过 程中不能发生任何转换。显然,这样的读写操作是 不能使用输入运算符 “” 和输出运算符 “” 完成 的。对二进制文件的读写操作有两种: 使用 get 函数和 put 函数读写单字节; 使用 read 函数和 write 函数读写指定长度的字节。, 使用 get 函数和 put 函数读写二进制文件 get 是 istream 类的成员函数

54、。函数原型: inline istream,功能:从输入流对象关联的文件中读数据, 每次读1字节,读指针自动增1。 put 是 ostream 类的成员函数。函数原型 inline ostream 功能:向输出流对象关联的文件中写数据, 每次写1字节,写指针自动增1。,例8-8一个实现任意文件复制的简单程序。 问题分析: 与例8-7相同也采用了命令行参数的形式,所 不同的是在执行程序时,命令行中应包含执行 文件名,源文件名和目标文件名。因此命令行 参数计数 argc = 3,执行文件名保存在 argv0 中,源文件名存放在 argv1 中,目标文件名 存放在 argv2 中。若执行文件名为 d

55、uplicate, 源文件名为 file,目标文件名为 file1,则执行 时的命令行应该是:duplicate file file1 如果命令行的参数个数不等于3,则显示命令 行格式提示并退出执行。, 二进制文件的处理过程与文本文件的处理过 程基本相同,但判断文件结束时有所区别: 文本文件:遇到文件结束符,get 函数返回文 件结束标志EOF,该标志值为 -1,它有别 于其它任何文本字符。 二进制文件:由于 -1 也是有效二进制数据, 所以不能使用 EOF 作为判断文件结束的标 志。为解决这个问题,应使用另一个成员 函数 eof,用来判断文件结束,其原型为: int eof(); 当到达文件

56、尾时,它返回 bool 值 true,否 则返回 false。,例8-9实现在屏幕上显示任何文件的内容。 注意:指定文件打开方式为 ios:binary 并不是按 二进制读写文件数据的必要条件。如果不存在对 二进制文件的特定判别问题,就不一定需要使用 ios:binary 方式打开文件。在例8-8和例8-9中,都 没有指定文件打开方式为 ios:binary。, 使用 read 函数和 write 函数读写二进制文件 read 是 istream 类的成员函数。函数原型: istream 功能:从相应的流中读取 num 个字节,并将 它们存放到指针 buf 所指的缓冲区中, 读指针自动增加 n

57、um 。 在调用该函数时,需要传递两个参数:缓冲 区的首地址和从文件中读取的字节数,,其调用格式如下: read(缓冲区首址, 读入的字节数); 注意:“缓冲区”的数据类型为 unsigned char, 如果读取的数据为其他类型时,则须进行类 型转换,例如: int array = 50, 60, 70; read(usigned char*), write 是 ostream 类的成员函数。函数原型: ostream 功能:从 buf 所指向的缓冲区中将 num 个字节 写到相应的文件中。写指针自动增加 num。 在调用该函数时,所需参数与 read 类似。,例8-10 用 write 函

58、数向文件 “test” 中写入双精度数 与字符串。 显然,该程序执行后,屏幕上将不会显示任何信 息,而且不能使用 DOS 系统的 type 命令或使用 Windows 平台的 “记事本” 或其他可以读写纯文本 文件的工具完全正确地查看文件 “test” 中记录的 信息,因为以二进制方式写入的双精度数是不可 能以文本方式被正确显示的。 例8-11 用 read 函数读取例8-10 程序所建立的的二 进制文件。,3 文件的随机读写 前面介绍过的文件操作,无论是文本文件还是二进 制文件,都是按顺序进行读写的。如果只能顺序读 写操作,那么读写文件中的特定位置的数据则需要 从文件开始顺序空读,直至读指针

59、或写写指针到达 要读或写的数据。这显然是极不方便的。 为了解决这一问题,增加文件访问的灵活性,流类 istream 和 ostream 提供了随机移动文件读指针或写 指针的成员函数,使得用户可以根据需要对文件中 任意位置的数据进行随机读写。,移动文件指针的成员函数是 seekg(移动读指针) seekp(移动写指针)。函数原型: istream 第一个参数:位移量 offset 的类型是 streamoff,该类 型在系统头文件 iostream.h 中定义为:,typedef long streamoff; 因此可以用 long 替代 streamoff。 第二个参数:移动文件指针的起始位置

60、。seek_dir 是 类 ios 中的枚举名: enum seek_dir beg = 0, cur = 1, end = 2 ; ios:beg 表示以文件头为起点,将读或写指针移 动由 offset(必须为正数)指定的距离。 ios:cur 表示以指针的当前位置为起点,将读或 写指针移动由 offset(可以为正数或负数)指定 的距离。 ios:end 表示以文件尾为起点,将读或写指针移 动由 offset(必须为负数或零)指定的距离。,获取读指针当前位置的成员函数是 tellg,而获取写 指针当前位置的成员函数是 tellp。函数原型: streampos tellg(); strea

61、mpos tellp(); typedef long streampos; 功能:返回读或写指针的当前位置。 例8-12 修改指定文件中指定位置的字符。 该程序也是一个命令行程序。例如,程序的执行文 件名为 change,需要修改的文本文件名为 file,文件 中要被改写的字符偏移量 byte = 5,修改后的字符为 “#”,则程序执行时的命令行为: change file 5 #,例8-13 使用 seekg 函数,指定文件读指针位置,并 从该指定位置开始显示文件内容。 该程序也是一个命令行程序。例如,程序的执行文 件名为 locate,要显示的文本文件名为 file,指定的 位置 loc

62、= 5,则程序执行时的命令行为: locate file 5 返回,8.4.3 使用 MFC 的对话框类实现输入输出 1创建能够使用 MFC 类的控制台程序项目 程序项目的创建过程中,选择 MFC 类库的支持。,在所创建的程序项目的 stdafx.h 文件中增加了如下代码: #include #include / MFC core and standard components #include / MFC extensions #ifndef _AFX_NO_OLE_SUPPORT #include / MFC support for Internet Explorer 4 / Common

63、 Controls #endif #ifndef _AFX_NO_AFXCMN_SUPPORT #include / MFC support for Windows Common / Controls #endif / _AFX_NO_AFXCMN_SUPPORT 用于提供使用 MFC 类库的支持。,在以项目名命名的源文件(例如 test.cpp)中提供如下缺省代码: #include stdafx.h #include test.h #ifdef _DEBUG #define new DEBUG_NEW #endif / The one and only application object CWinApp theApp; using namespace std; / parameters:stack - reference of stack object int _tmain(int argc, TCHAR* argv, TCHAR* envp) int nRetCode = 0;,/ initialize MFC and print and error on failure if (!AfxWinInit

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

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!