《第九章流类库和输入输出宿州学院.ppt》由会员分享,可在线阅读,更多相关《第九章流类库和输入输出宿州学院.ppt(79页珍藏版)》请在三一办公上搜索。
1、第九章 流类库和输入/输出,本章的最主要目的就是把对象保存到磁盘文件中并从磁盘文件重建对象。C+语言中并没有输入/输出语句,而是在标准库里包含了一个I/O流类库,它与标准模板库同为C+标准库中最重要的组成部分。数据从一个对象到另一个对象的传送被抽象为“流”。数据的输入/输出就是通过输入/输出流来实现的。流是一种抽象的概念,负责在数据的产生者和数据的使用者之间建立联系,并管理数据的流动。,第九章 流类库和输入/输出,9.1 C+的基本流类体系,9.3 标准设备的输入/输出,9.2 输入输出的格式控制(选读),9.4 文件的输入与输出,9.5 字符串流(选读),9.6 文件与对象,9.1 C+的基
2、本流类体系,流类体系:以抽象类模板basic_ios为基类,流类模板派生体系见图9.1。整个流类模板体系的标准I/O在头文件中说明,它包含头文件、和。而输入输出文件流部分在头文件中说明。,图9.1 主要输入/输出流模板层次,9.1 C+的基本流类体系,basic_ios类模板提供了对流进行格式化输入输出和错误处理的成员函数。所有派生都是公有派生。basic_istream类模板提供完成提取(输入)操作的成员函数,而basic_ostream类模板提供完成插入(输出)操作的成员函数。basic_iostream类本质上是前两者的聚合,并没有增加成员。派生全部为公有派生。有关模板派生请参见教学指导
3、书第8章中“类模板的派生的讨论”,basic_streambuf不是basic_ios的派生类,而是一个独立的类,只是basic_ios有一个保护访问限制的指针指向它。类basic_streambuf的作用是管理一个流的缓冲区。,流类体系说明:,9.1 C+的基本流类体系,标准输入/输出流对象:在C+的流类库中定义了四个全局流对象:cin,cout,cerr和clog。可以完成人机交互的功能。cin标准输入流对象,键盘为其对应的标准设备。cout标准输出流对象,显示器为标准设备。cerr和clog标准错误输出流,输出设备是显示器。其中cin、cout和clog是带缓冲区的,缓冲区由stream
4、buf类对象来管理。而cerr为非缓冲区流,一旦错误发生立即显示。要使用这四个功能,必须包含文件。,9.1 C+的基本流类体系,重载的提取运算符“”(stream_extraction operator)和插入运算符“”(stream_insertion operator),执行输入/输出操作。“提取”的含义是指输入操作,可看作从流中提取一个字符序列。“插入”的含义是指输出操作,可看作向流中插入一个字符序列。cin使用提取运算符。cout、cerr和clog使用插入运算符。文件:文件处理完成永久保存的功能。在Windows下不同的C+平台,都为文件功能作了扩充,在VC+的MFC编程中采用了序列
5、化(Serialization)。,提取运算符和插入运算符:,9.2 输入输出的格式控制(选读),enum skipws=0 x0001,/跳过输入中的空白字符 left=0 x0002,/输出左对齐 right=0 x0004,/输出右对齐 internal=0 x0008,/在输出符号或数制字符后填充 dec=0 x0010,/在输入输出时将数据按十进制处理 oct=0 x0020,/在输入输出时将数据按八进制处理 hex=0 x0040,/在输入输出时将数据按十六进制处理,格式控制符:C+在类ios_base中提供格式化输入输出。这些格式是对所有文本方式的输入输出流均适用。格式控制符定义
6、为公有的无名枚举类型,在VC+6.0中定义为:,9.2 输入输出的格式控制(选读),showbase=0 x0080,/在输出时带有表示数制基的字符 showpoint=0 x0100,/输出浮点数时,必定带小数点 uppercase=0 x0200,/输出十六进制,用大写 showpos=0 x0400,/输出正数时,加”+”号 scientific=0 x0800,/科学数方式输出浮点数 fixed=0 x1000,/定点数方式输出实数 unitbuf=0 x2000,/插入后,立即刷新流 stdio=0 x4000/插入后,立即刷新stdout和stderr,对不同的C+平台,枚举常量名
7、相同,但所取值及枚举类型名不一定相同。后文的枚举常量也是如此。为保证通用性,实际只用枚举常量名而不用数值 空白字符包括:空格、制表、垂直制表、换行、换页和回车。,9.2 输入输出的格式控制(选读),该枚举量说明中每一个枚举量实际对应两字节数据(16位)中的一个位,所以可以同时采用几个格式控制,只要把对应位置1即可,这样既方便又节约内存。取多种控制时,用或“|”运算符来合成,合成为一个长整型数,在ios中为:protected:long x_flags;,点击访问x_flags的重载函数定义,9.2 输入输出的格式控制(选读),输入输出流格式控制标志:protected:int x_precis
8、ion;/标志浮点数精度,默认为6位 int x_width;/输出域宽,默认域宽为0,/重设域宽只对其后第一输出项有效,如域宽不足,则不受限制 char x_fill;/标志域宽有富余时填入的字符,点击访问格式控制标志相关接口函数,【例9.1】整型数输出。,【例9.2】浮点数输出。,9.2 输入输出的格式控制(选读),【例9.2】程序执行后输出:默认域宽为:0位默认精度为:6位默认表达方式:31.4159科学数表达方式:3.141593e+001定点表达方式:31.4159279位科学数表达方式:3.141592654e+001,流操作子(setiosflags stream manipul
9、ator):可代替流格式控制成员函数点击查阅流操作子【例9.2_1】采用流操作子的浮点数输出。,9.3 标准设备的输入/输出,本节对cin,cout,cerr和clog,提取和插入运算符(和)的使用的细节作进一步的讨论。,9.3.2 标准输入/输出成员函数(选读),9.3.1 提高标准输入/输出的稳健性,9.3.3 重载插入和提取运算符,状态字state为整型,其的各位在ios中说明:enum ios_state goodbit=0 x00,/流正常 eofbit=0 x01,/输入流结束忽略后继提取操作;或文件结束已无数据可取 failbit=0 x02,/最近的I/O操作失败,流可恢复 b
10、adbit=0 x04,/最近的I/O操作非法,流可恢复 hardfail=0 x08/I/O出现致命错误,流不可恢复,/VC6.0+和标准C+不支持,9.3.1 提高标准输入/输出的稳健性,点击查看读取状态的有关操作,程序运行状态:,对于流,只要出错,对应流的状态标志就设置为1,此后忽略所有对该流对象的操作,必须用clear()函数清0,然后才能正常运行。,9.3.1 提高标准输入/输出的稳健性,标准设备输入使用要点:cin为缓冲流。键盘输入的数据保存在缓冲区中,当要提取时,是从缓冲区中拿。如果一次输入过多,会留在那儿慢慢用,如果输入错了,必须在回车之前修改,如果回车键按下就无法挽回了。只有
11、把输入缓冲区中的数据取完后,才要求输入新的数据。不可能用刷新来清除缓冲区,所以不能输错,也不能多输!输入的数据类型必须与要提取的数据类型一致,否则出错。出错只是在流的状态字state(枚举类型io_state)中对应位置位(置1),程序继续。所以要提高稳健性,就必须在编程中加入对状态字state的判断。错误更正后,流的状态字state中对应位不会自动清除,必须软件清0。,9.3.1 提高标准输入/输出的稳健性,3.空格和回车都可以作为数据之间的分格符,所以多个数据可以在一行输入,也可以分行输入。但如果是字符型和字符串,则空格(ASCII码为32)无法用cin输入,字符串中也不能有空格。回车符也
12、无法读入。4.输入数以后再输入字符或字符串:如果数后直接加回车,应该用cin.get()提取回车。如果还有空格,则要清空缓冲区。,【例9.3】提高输入的稳健性。输入时需要故意输错,以测试稳健性。,9.3.2 标准输入/输出成员函数(选读),输入流成员函数声明:字符输入:int istream:get();/提取一个字符,包括空格,制表,垂直制表、换页、/换行和回车等,与cin有所不同。注意返回为整型。istream/提取一个字符,放在字符型变量中。单参数,并为字符的引用。,9.3.2 标准输入/输出成员函数(选读),字符串输入:istream 提取的串放在第一个参数为开始地址的存储区中(不查边
13、界);第二个参数为至多提取的字符个数(指定为n,最多取n-1个,再加一个字符串结束符);第三个参数为结束字符,遇此字符则结束,默认为回车换行符。,9.3.2 标准输入/输出成员函数(选读),字符串输入:当3参数get()系列函数读到结束字符则停止读入,但不提取结束字符。结束字符要求单独提取(常用回车符,不单独提取回车符,以后会连续读入空串),而且必须使用单参数get()函数或下文的ignore()函数提取结束字符。getline提取字符串时如遇到指定结束符则提取该结束符,但不保存在串中。这两个函数都会在提取的一系列字符后加一个串结束符,返回值为对象本身(*this)。,如果用VC+标准库函数,
14、即用头文件iostream时,对3参数get()系列函数和getling()函数,当第二个参数为n,而实际输入n个或更多字符,函数未能读到结束字符而停止,流出错(输入输出操作失败),后面不再读入,必须清除流状态字,后面的字符才能继续读入。,9.3.2 标准输入/输出成员函数(选读),其他函数:函数gcount()返回最后一次提取的字符数量,包括回车:int istream:gcount();函数ignore()读空(指定一个大的数量)缓冲区:istream第一个参数为要提取的字符数量,默认为1;第二个参数为结束字符,提取该结束字符,但对所提取的字符不保存不处理,作用是空读。第二个参数的默认值E
15、OF为文件结束标志。,在iostream中EOF定义为-1,在int get()函数中,读入输入流结束标志Ctrl+Z(Z)时,函数返回EOF,为了能表示EOF的“-1”值,返回类型为int。采用cin.eof()函数,当前所读为EOF则返回非零,注意函数自身未从流中读取。,【例9.4】ignore()和gcount()函数使用。,9.3.2 标准输入/输出成员函数(选读),输出流成员函数声明:ostream/刷新一个输出流,用于cout和clog,9.3.3 重载插入和提取运算符,重载插入和提取运算符:重载必须保留原来的使用特性。重载只能在用户定义类中,将重载的运算符的函数说明为该类的友元函
16、数:friend istream函数的返回值是对输入或输出流的引用,这是为了保证在cin和cout中可以连续使用“”或“”和“”或“”的左操作数;第二个参数为用户定义类的引用,作为右操作数。流用作函数参数,必须是引用调用,不能是传值调用。因为这里要求处理流本身,而不是副本。,【例9.5】改进自定义字符串类,重载插入运算符“”。【例9.6】用户定义的复数类Complex的输入与输出。,9.4 文件的输入与输出,本节中文件指的是磁盘文件。C+根据文件(file)内容的数据格式,可分为两类:二进制文件和文本文件。文本文件由字符序列组成,也称ASCII码文件,在文本文件中存取的最小信息单位为字符(ch
17、aracter),而二进制文件中存取的最小信息单位为字节(Byte)。,C+把每一个文件都看成一个有序的字节流,见图9.2,每一个文件或者以文件结束符(end of file marker)结束,或者在特定的字节号处结束。,文件的基本概念:,9.4 文件的输入与输出,当打开一个文件时,该文件就和某个流关联起来了。对文件进行读写实际上受到一个文件定位指针(file position pointer)的控制。输入流的指针也称为读指针,每一次提取操作将从读指针当前所指位置开始,每次提取操作自动将读指针向文件尾移动。输出流指针也称写指针,每一次插入操作将从写指针当前位置开始,每次插入操作自动将写指针向
18、文件尾移动。,9.4.1 文件的打开与关闭,9.4.2 文本文件的读写,9.4.3 二进制文件的读写,9.4.4 文件的随机访问(选读),9.4.1 文件的打开与关闭,文件使用步骤:1说明一个文件流对象,这又被称为内部文件:ifstream ifile;/只输入用ofstream ofile;/只输出用fstream iofile;/既输入又输出用,9.4.1 文件的打开与关闭,2使用文件流对象的成员函数打开一个磁盘文件。这样在文件流对象和磁盘文件名之间建立联系。文件流中说明了三个打开文件的成员函数。void ifstream:open(const char*,int=ios:in,int=f
19、ilebuf:openprot);void ofstream:open(const char*,int=ios:out,int=filebuf:opernprot);void fstream:open(const char*,int,int=filebuf:openprot);第一个参数为要打开的磁盘文件名。第二个参数为打开方式,有输入(in),输出(out)等,打开方式在ios基类中定义为枚举类型。第三个参数为指定打开文件的保护方式,一般取默认。所以第二步可如下进行:iofile.open(“myfile.txt”,ios:in|ios:out);,文件打开方式:是由在ios类中定义的公有枚
20、举成员决定:enum open_mode in=0 x01,out=0 x02,ate=0 x04,app=0 x08,trunc=0 x10,binary=0 x80;,9.4.1 文件的打开与关闭,in标识打开文件用于输入操作(从文件读取)。打开方式只要含in,如文件不存在则返回失败。在打开为输入输出方式时(同时用out),编程应注意判断是否失败,失败时千万不可再写入文件。out标识打开文件用于输出操作(写入文件)。如文件不存在,则建立新文件,如文件存在,未同时设app,in则文件清空。trunc标识打开文件,并清空它(文件长度截为0)。文件不存在则建立新文件,与out默认操作相同。但与i
21、n配合,文件不存在则返回失败。app标识打开文件用于输出,原文件内容保留,新数据接在尾部 ate意思是at end,标识打开文件,文件指针在文件尾,但文件指针可以移动,即新数据可写到任何位置。文件是否清空由其它标识决定。后三个标识最好配合out、in等一起用,因为不同的C+平台,要求不同,一起用不会出错。如不一起用,至少VC+不认这种格式。binary标识以二进制方式打开文件。同时用out时,如文件不存在,则建立新文件,并且新文件能用,不必清状态字。,打开方式解释:,9.4.1 文件的打开与关闭,三个文件流类都重载了一个带默认参数的构造函数,功能与open函数一样:ifstream:ifstr
22、eam(const char*,int=ios:in,int=filebuf:openprot);ofstream:ofstream(const char*,int=ios:out,int=filebuf:openprot);fstream:fstream(const char*,int,int=filebuf:operprot);所以1,2两步可合成:fstream iofile(”myfile.txt”,ios:in|ios:out);,9.4.1 文件的打开与关闭,打开文件也应该判断是否成功,若成功,文件流对象值为非零值,不成功为0(NULL),文件流对象值物理上就是指它的地址。因此打开
23、一个文件完整的程序为:fstream iofile(”myfile.txt”,ios:in|ios:out);if(!iofile)/“!”为重载的运算符,见9.3.1节 cout”不能打开文件:”myfile.txt”endl;return-1;/失败退回,9.4.1 文件的打开与关闭,使用提取和插入运算符对文件进行读写操作,或使用成员函数进行读写,这在下一节中讨论。关闭文件。三个文件流类各有一个关闭文件的成员函数:void ifstream:close();void ofstream:close();void fstream:close();使用很方便,如:iofile.close();,
24、9.4.1 文件的打开与关闭,关闭文件时,系统把该文件相关联的文件缓冲区中的数据写到文件中,保证文件的完整,收回与该文件相关的内存空间,可供再分配,把磁盘文件名与文件流对象之间的关联断开,可防止误操作修改了磁盘文件。如又要对文件操作必须重新打开。关闭文件并没有取消文件流对象,该文件流对象又可与其他磁盘文件建立联系。文件流对象在程序结束时,或它的生命期结束时,由析构函数撤消。它同时释放内部分配的预留缓冲区。,9.4.2 文本文件的读写,文本文件的顺序读写:顺序读写可用C+的提取运算符()和插入运算符(”完成重构对象,而只用一个“”完成对象存入文件。,9.4.2 文本文件的读写,文本数据文件的读写
25、:按C+的常规,资源获取是由构造函数实现,而资源释放是由析构函数完成。所以与内存动态分配一样,由文件重构对象放在构造函数中,把对象存入文件则放在析构函数中。详细内容见9.6节,更深层次的理由见下一章异常处理。【例9.9】只是为了更清楚地显示文件的操作,常规做法请读者参见【例9.13】。,9.4.3 二进制文件的读写,对二进制文件进行读写的成员函数:istream/第一个参数指定输出对象的内存地址,必须强制转换为char*类型/第二个参数指定插入的字节数,/函数从该地址开始将指定数量的字节插入输入输出流,9.4.3 二进制文件的读写,文件结束判断:读函数并不能知道文件是否结束,可用状态函数int
26、 ios:eof()来判断文件是否结束。必须指出系统是根据当前操作的实际情况设置状态位,如需根据状态位来判断下一步的操作,必须在一次操作后立即去调取状态位,以判断本次操作是否有效。,【例9.10】创建二进制数据文件,以及数据文件的读取。这两项操作设计为成员函数。给出与【例9.9】不同的读写方式:,9.4.3 二进制文件的读写,二进制文件优点:可以控制字节长度,读写数据时不会出现二义性,可靠性高。同时不知格式是无法读取的,保密性好。文件结束后,系统不会再读(见eofbit的说明),但程序不会自动停下来,所以要判断文件中是否已没有数据。如写完数据后没有关闭文件,直接开始读,则必须把文件定位指针移到
27、文件头。如关闭文件后重新打开,文件定位指针就在文件头。,9.4.4 文件的随机访问(选读),文件的随机访问:在C+中可以由程序控制文件指针的移动,从而实现文件的随机访问,即可读写流中任意一段内容。一般文本文件很难准确定位,所以随机访问多用于二进制文件。如【例9.9】中对象中两个字符串是按实际串长存放的,不是按数组元素来存放的,而【例9.10】中是按数组长度来存放的,每个对象数据长度固定,所以便于随机访问。,在ios类中说明了一个公有枚举类型:enum seek_dirbeg=0,/文件开头cur=1,/文件指针的当前位置end=2/文件结尾;,随机访问指针控制字:,9.4.4 文件的随机访问(
28、选读),输入流指针控制字设置成员函数:istream/表示将文件定位指针从文件尾向文件头方向移20个字节。tellg()和seekg()往往配合使用。/指针不可移到文件头之前或文件尾之后。,9.4.4 文件的随机访问(选读),输入流指针控制字设置成员函数:ostream 为了便于记忆,函数名中g是get的缩写,而p是put的缩写。对输入输出文件定位指针只有一个但函数有两组,这两组函数功能完全一样。,【例9.11】使用随机访问对【例9.10】进行改造。,9.5 字符串流(选读),字符流概念:字符串(string)也可以看作字符流。可以用输入输出操作来完成串流的操作。串流与内存相关,所以也称内存流
29、。串流类包括ostrstream、istrstream、strstream,它们在中说明。串流类对象可以保存字符,也可以保存整数、浮点数。串流类对象采用文本方式。其构造函数常用下面几个:istrstream:istrstream(const char*str);istrstream:istrstream(const char*str,int);ostrstream:ostrstream(char*,int,int=ios:out);strstream:strstream(char*,int,int);其中第二个参数说明数组大小,第三参数为文件打开方式。,【例9.12】,9.6 文件与对象,在面
30、向对象的C+程序设计中,文件应该在构造函数中打开,并创建对象;而在析构函数中保存和关闭文件,并撤销对象。当撤销对象时,能自动释放资源。释放资源包括将对象中的信息再次存入磁盘文件。程序运行中,总要对保存在对象的数据成员里的信息进行操作,这时应该将信息适时保存到相应的磁盘文件中,以免数据意外丢失。这些都是常规操作,是面向对象的C+程序设计的固定框架。,规范化操作:在面向对象的程序设计中,信息总是放在对象的数据成员里。这些信息最终应该保存到文件中。当程序开始运行时要由打开的文件重新创建对象。在运行过程中,放在对象的数据成员里的信息得到利用和修改。运行结束时必须把这些信息重新保存到文件中,然后关闭文件
31、。,9.6 文件与对象,【例9.13】将商店的货物,定义为一个货物数组类。数组对象动态建立,初始为2个元素,不够用时扩充一倍。用文本数据文件建立数组元素对象,要求放在构造函数中,而数据的保存和文件的关闭放在析构函数中。第一次运行时,建立空的数据文件,由键盘输入建立数组元素对象,并写入文件,程序退出时,关闭文件;下一次运行由该文件构造对象,恢复前一次做过的工作。,这是一个标准的面向对象的程序设计,也是对前面各章内容的小结。注意,本例使用了多重的插入运算符重载。,第九章 流类库和输入/输出,结束,谢谢!,9.2 输入输出的格式控制(选读),访问x_flags的重载函数声明如下:inline lon
32、g ios:flags()const;/返回当前标志字inline long ios:flags(long);/把参数作为新的标志字,并返回原标志字(下同)inline long ios:setf(long,long);/在原标志字上增加控制,/第一个参数为增加的控制,第二个参数表示取代原来哪几位inline long ios:setf(long);/增加控制(多项)inline long ios:unsetf(long);/清除指定位上的控制,9.2 输入输出的格式控制(选读),相关接口函数为:inline int ios:width()const;/返回当前域宽inline int ios
33、:width(int);/把参数作为新的域宽,返回原域宽inline char ios:fill()const;/返回当前填充字符inline char ios:fill(char);/参数为新填充字符,返回原填充字符inline int ios:precision(int);/参数作为新精度,返回原精度inline int ios:precision()const;/返回当前精度,9.2 输入输出的格式控制(选读),【例9.1】整型数输出。#includeusing namespace std;int main(void)int inum=255;cout十进制方式inumt;cout.fl
34、ags(ios:oct|ios:showbase);/八进制带数制基输出是前面加0;对VC+参数等效0 x00a0cout八进制方式inumt;cout.setf(ios:hex,ios:basefield);/basefield代表控制/进位基制的三位ios:dec|ios:oct|ios:hex。/因是或关系,仍带基输出,格式为0 x.cout十六进制方式inumendl;return 0;,程序输出:十进制方式255 八进制方式0377 十六进制方式0 xff,9.2 输入输出的格式控制(选读),【例9.2】浮点数输出。int main()double fnum=31.415926535
35、;cout默认域宽为:cout.width()位n;cout默认精度为:cout.precision()位n;cout默认表达方式:fnumn;/按值大小,自动决定定点还是科学数方式cout.setf(ios:scientific,ios:floatfield);cout科学数表达方式:fnumn;cout.setf(ios:fixed,ios:floatfield);/设为定点,取消科学数方式cout定点表达方式:fnumn;cout.precision(9);/精度9位指小数点后9位cout.setf(ios:scientific,ios:floatfield);cout 9位科学数表达方
36、式fnumn;return 0;,其中floatfield代表浮点数的两控制位ios:scientific|ios:fixed为了避免浮点数互相冲突的双重规定,所以先清除原浮点数两个输出控制位,再用新的一位去代替。,9.2 输入输出的格式控制(选读),流操作子(setiosflags stream manipulator)可代替流格式控制成员函数。它们的使用格式如第一章所介绍的setw()等使用的格式。注意,绝大多数流操作子仅适用于新的C+标准流类库(头文件不带.h)。,cin,cout和clog都是缓冲流。对输出而言,仅当输出缓冲区满才将缓冲区中的信息输出,对输入而言,仅当输入一行结束,才开
37、始从缓冲区中取数据,当希望把缓冲区中的信息立即输出,可用flush,加endl也有同样功能,回车并立即显示,不必等缓冲区满(endl清空缓冲区)。,9.2 输入输出的格式控制(选读),【例9.2_1】采用流操作子的浮点数输出。#include#includeusing namespace std;int main()double fnum=31.415926535;cout默认域宽为:cout.width()位n;cout默认精度为:cout.precision()位n;cout默认表达方式:fnumn;/按值大小,自动决定定点还是科学数方式 cout科学数表达方式:scientificfnu
38、mn;/设为科学数方式 cout定点表达方式:fixedfnumn;/设为定点,取消科学数方式 cout9位科学数表达方式setprecision(9)scientificfnumn;return 0;,读取状态的有关操作如下:inline int ios:rdstate()const return state;/读取状态字inline int ios:operator!()constreturn state/正常返回1,否则返回0,9.3.1 提高标准输入/输出的稳健性,【例9.3】提高输入的稳健性。int main()char str256;int i;couti;/可故意输入若干非数字字
39、符,下次再输入若干字符加数字串/加若干非数字字符进行检测 while(cin.fail()couti;cin.getline(str,256);/读空缓冲区,吃掉回车符 cout请输入字符串endl;cin.getline(str,255);cout输入整数为:iendl;cout输入字符串为:strendl;return 0;,9.3.2 标准输入/输出成员函数(选读),【例9.4】ignore()和gcount()函数使用。int main()char str255;int i,n;cout输入字符endl;/输入Z,一旦输入Z全部结束,不能输入其它字符 i=cin.get();coute
40、ndl;n=cin.rdstate();/读取状态字 cout状态字为:nendl;/状态字为1,流结束 cout当输入字符时,取得的是:iendl;/-1,输入Z时,返回EOF,即-1 if(n=0)cin.ignore(255,n);/清除多余的字符和回车符 cin.clear(0);/A 使流恢复正常 cout输入字符串1:endl;cin.getline(str,255);coutendl;,9.3.2 标准输入/输出成员函数(选读),cout状态字为:cin.rdstate()endl;i=cin.gcount();cout字符串为:strt读入字符数为:it;cout串长为:str
41、len(str)endl;cin.clear(0);/A 使流恢复正常 cout输入字符串2:endl;cin.getline(str,255);coutendl;cout状态字为:cin.rdstate()endl;i=cin.gcount();cout字符串为:strt读入字符数为:it;cout串长为:strlen(str)endl;return 0;注意,若无两个A行,输入Z后,不再理会余下的所有输入。,9.3.3 重载插入和提取运算符,【例9.5】改进自定义字符串类,重载插入运算符“void Orderedlist:print()int i;for(i=0;i=last;i+)cou
42、tslisti.key;if(i%5=4)coutendl;coutendl;更重要的是不用show()函数,格式一致了,可以同时用于基本数据类型,如整型、实型、字符型,也可用于标准字符串string。,【例9.6】用户定义的复数类型Complex的输入与输出。#includeusing namespace std;class Complex double Real,Image;public:Complex(double r=0.0,double i=0.0):Real(r),Image(i)/这里省略若干成员函数,以节约篇幅,详见【例4.7】friend ostream,9.3.3 重载插入
43、和提取运算符,istream,9.3.3 重载插入和提取运算符,putback()声明如下:stream它将最后一次从输入流中得到的字符放回到输入流中。,int main()Complex a,b,c;couta;coutb;coutc;couta=atb=bt c=cn;return 0;,9.3 标准设备的输入/输出,9.4.2 文本文件的读写,【例9.7】复制文件。int main()char ch;ifstream sfile(d:Ex9_6Ex9_6.cpp);ofstream dfile(e:Ex9_6.cpp);/只能创建文件,不能建立子目录,如路径不存在则失败 if(!sfil
44、e)coutch)dfilech;sfile.close();/如没有这两个关闭函数,析构函数也可关闭 dfile.close();return 0;,9.4.2 文本文件的读写,首先必须设置关闭跳过空白,因为提取(“”)运算符在默认情况下是跳过空白字符的,这样复制的文件会缺少一些字符。第二,该程序能确定文件是否复制结束。流类成员函数和运算符全是返回本类型的引用,这里就是流文件对象自身,当文件结束时,返回NULL,这时不再复制,退出循环。第三,复制是按字节进行的,效率很低,按字节传递开销极大,但该程序能正确复制任意类型的文件,不仅是文本文件(看作按字符),二进制文件(看作按字节)也一样可正确完
45、成。如果是文本文件,我们可以按行进行复制。第四,!sfile中的!是重载的运算符,在状态函数中重载,当该操作出现不正常状态,返回操作非法和操作失败这两位。,【例9.8】按行复制文本文件。int main()char filename256,buf100;fstream sfile,dfile;coutfilename;/对路径名而言空格是无关紧要的,否则要用getline()等成员函数 sfile.open(filename,ios:in);/打开一个已存在的文件 while(!sfile)coutfilename;sfile.open(filename,ios:in);coutfilenam
46、e;/只能创建文件,不能建立子目录,如路径不存在则失败,dfile.open(filename,ios:out);if(!dfile)cout目标文件创建失败endl;return-1;while(sfile.getline(buf,100),sfile.eof()!=1)/按行复制 A行 if(sfile.rdstate()=0)dfilebufn;/因读到回车符,提取但未保存 B行 else dfilebuf;sfile.clear(0);/流不正常,/还未读到回车换行符,所以不加n。状态字被置为failbit,必须清0 sfile.close();dfile.close();return
47、 0;,A行中sfile.getline(buf,100)从源文件读一行字符,或读99个字符,效率大大提高。B行中,因从源文件读字符是遇到行结束(回车换行)符停止的,所以文件中应有一个回车换行符;但getline()回车换行符并不放在buf中,因此要加一个回车换行符,但此程序只能用于文本文件。,9.4.2 文本文件的读写,【例9.9】文本式数据文件的创建与读取数据。典型的C+数据存入文件和由文件获得数据的方法是把对象存入文件和由文件重构对象。本例对提取和插入运算符进行了重载,只用一个“”完成重构对象,而只用一个“(istream/流类作为形式参数必须是引用,9.4.2 文本文件的读写,inve
48、ntory:inventory(string des,string no,int quan,double cost,double ret)Description=des;No=no;Quantity=quan;Cost=cost;Retail=ret;ostream/从文件读出是自动把数字串转为数读出,/函数体内功能不变,会自动转换,9.4.2 文本文件的读写,int main()inventory car1(夏利2000,805637928,156,80000,105000),car2;inventory motor1(金城125,93612575,302,10000,13000),moto
49、r2;ofstream destfile(d:Ex9_9.data);destfilecar2motor2;sourfile.close();coutcar2;coutmotor2;return 0;,9.4.3 二进制文件的读写,【例9.10】创建二进制数据文件,及数据文件的读取。类inventory与【例9.9】基本一样,只是用二进制文件的Bdatatofile()和Bdatafromfile()取代了文本文件的提取运算符和插入运算符。void inventory:Bdatatofile(ofstream,9.4.3 二进制文件的读写,void inventory:Bdatafromfil
50、e(ifstream/读和写是完全对称的过程,次序决不能错,9.4.3 二进制文件的读写,int main()inventory car1(夏利2000,805637928,156,80000,105000),car2;inventory motor1(金城125,93612575,302,10000,13000),motor2;ofstream ddatafile(d:Ex9_10.data,ios:out|ios:binary);car1.Bdatatofile(ddatafile);motor1.Bdatatofile(ddatafile);cout对象car1:endl;coutcar