输入输出流类库.ppt_第1页
输入输出流类库.ppt_第2页
输入输出流类库.ppt_第3页
输入输出流类库.ppt_第4页
输入输出流类库.ppt_第5页
已阅读5页,还剩78页未读 继续免费阅读

下载本文档

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

文档简介

第九章 流类库和输入/输出,本章的最主要目的就是把对象保存到磁盘文件中并从磁盘文件重建对象。当然C+可完成更多的任务。 C+语言中并没有输入/输出语句,而是在标准库里包含了一个I/O流类库,它与标准模板库同为C+标准库中最重要的组成部分。数据从一个对象到另一个对象的传送被抽象为“流”。数据的输入/输出就是通过输入/输出流来实现的。 流是一种抽象的概念,负责在数据的产生者和数据的使用者之间建立联系,并管理数据的流动。,第九章 流类库和输入/输出,9.1 C+的基本流类体系,9.3 标准设备的输入/输出,9.2 输入输出的格式控制,9.4 文件的输入与输出,9.7 图书馆流通管理系统设计 输出/输入流的应用,9.5 字符串流(内存流),9.6 MFC中的文件处理,9.1 C+的基本流类体系,整个流类体系是一个派生类体系。按ANSI C+标准,类ios是抽象类,它的析构函数是虚函数,它的构造函数为保护的,作为所有基本流类的基类。VC+中有一个构造函数ios (streambuf*)为公有,与ANSI C+不同。,图9.1 输入/输出流类派生体系,9.1 C+的基本流类体系,图9.2 输入/输出流类层次,streambuf是一个独立的类,只是ios有一个保护访问限制的指针指向它。streambuf的作用是管理一个流的缓冲区。,ios提供了对流进行格式化输入输出和错误处理的成员函数。所有派生都是公有派生。istream类提供完成提取(输入)操作的成员函数,而ostream类提供完成插入(输出)操作的成员函数。iostream类是前两者的组合。,9.1 C+的基本流类体系,在流类库中,最重要的两部分功能为标准输入/输出(standard input/output)和文件处理。 在C+的流类库中定义了四个全局流对象:cin,cout,cerr和clog。可以完成人机交互的功能。 cin标准输入流对象,键盘为其对应的标准设备。 cout标准输出流对象,显示器为标准设备。 cerr和clog标准错误输出流,输出设备是显示器。 其中cin、cout和clog是带缓冲区的,缓冲区由streambuf类对象来管理。而cerr为非缓冲区流,一旦错误发生立即显示。 要使用这四个功能,必须包含文件。,9.1 C+的基本流类体系,提取运算符“”(stream_extraction operator)和插入运算符“”(stream_insertion operator),执行输入/输出操作。 “提取”的含义是指输入操作,可看作从流中提取一个字符序列。 “插入”的含义是指输出操作,可看作向流中插入一个字符序列。 文件处理完成永久保存的功能。在VC+的MFC编程中采用了序列化(Serialization)。,9.2 输入输出的格式控制,enum skipws=0x0001, /跳过输入中的空白字符 left=0x0002, /输出左对齐 right=0x0004, /输出右对齐 internal=0x0008, /在输出符号或数制字符后填充 dec=0x0010, /在输入输出时将数据按十进制处理 oct=0x0020, /在输入输出时将数据按八进制处理 hex=0x0040, /在输入输出时将数据按十六进制处理 showbase=0x0080, /在输出时带有表示数制基的字符,C+在类ios中提供格式化输入输出。这些格式是对所有文本方式的输入输出流均适用。格式控制符定义为公有的无名的枚举类型:,9.2 输入输出的格式控制,showpoint=0x0100, /输出浮点数时,必定带小数点 uppercase=0x0200, /输出十六进制,用大写 showpos=0x0400, /输出正数时,加”+”号 scientific=0x0800, /科学数方式输出浮点数 fixed=0x1000, /定点数方式输出实数 unitbuf=0x2000, /插入后,立即刷新流 stdio=0x4000 /插入后,立即刷新stdout和stderr,该枚举量说明中每一个枚举量实际对应两字节数据(16位)中的一个位,所以可以同时采用几个格式控制,只要把对应位置1即可,这样既方便又节约内存。取多种控制时,用或“|”运算符来合成,合成为一个长整型数,在ios中为: protected: long x_flags;,9.2 输入输出的格式控制,类ios中还设置了三个输入输出流格式控制标志: protected: int x_precision; /标志浮点数精度,缺省为6位 int x_width; /输出域宽,缺省域宽为0, /重设域宽只对其后第一输出项有效,如域宽不足,则不受限制 char x_fill; /标志域宽有富余时填入的字符,点击访问x_flags的重载函数定义,点击访问格式控制标志相关接口函数,【例9.1】整型数输出。,【例9.2】浮点数输出。,9.2 输入输出的格式控制,程序执行后输出: 缺省域宽为:0位 缺省精度为:6位 缺省表达方式:31.4159 科学数表达方式:3.141593e+001 定点表达方式:31.415927 9位科学数表达方式:3.141592654e+001,流操作子(setiosflags stream manipulator)可代替流格式控制成员函数: 点击查阅流操作子,9.3 标准设备的输入/输出,标准设备输入是最不安全的,注意以下几点,可以避免错误: 1. cin为缓冲流。键盘输入的数据保存在缓冲区中,当要提取时,是从缓冲区中拿。如果一次输入过多,会留在那儿慢慢用,如果输入错了,必须在回车之前修改,如果回车键按下就无法挽回了。只有把输入缓冲区中的数据取完后,才要求输入新的数据。不可能用刷新来清除缓冲区,所以不能输错,也不能多输!,9.3 标准设备的输入/输出,2. 输入的数据类型必须与要提取的数据类型一致,否则出错。出错只是在流的状态字state(枚举类型io_state)中对应位置位(置1),程序继续。所以要提高健壮性,就必须在编程中加入对状态字state的判断。 3. 空格和回车都可以作为数据之间的分格符,所以多个数据可以在一行输入,也可以分行输入。但如果是字符型和字符串,则空格(ASCII码为32)无法用cin输入,字符串中也不能有空格。回车符也无法读入。,状态字state为整型,其的各位在ios中说明: enum ios_state goodbit=0x00, /流正常 eofbit=0x01, /输入流结束忽略后继提取操作;或文件结束已无数据可取 failbit=0x02, /最近的I/O操作失败,流可恢复 badbit=0x04, /最近的I/O操作非法,流可恢复 hardfail=0x08 / I/O出现致命错误,流不可恢复,VC+不支持,9.3 标准设备的输入/输出,点击查看读取状态的有关操作,【例9.3】提高输入的健壮性。输入时需要故意输错,以测试健壮性。,9.3 标准设备的输入/输出,全面介绍输入输出流中的成员函数 输入流成员函数声明: 字符输入: istream 提取一个字符,放在字符型变量中,9.3 标准设备的输入/输出,字符串输入: istream 提取的串放在第一个参数为开始地址的存储区(不查边界);第二个参数为至多提取的字符个数(指定为n,最多取n-1个,再加一个字符串结束符);第三个参数为结束字符,遇此字符则结束,缺省为回车换行符。 get系列函数要求单独提取结束字符。getline提取字符串时如遇到指定结束符则提取该结束符,但不保存在串中。这两个函数都会在提取的一系列字符后加一个串结束符,返回值为对象本身(*this)。,9.3 标准设备的输入/输出,返回最后一次提取的字符数量,包括回车的函数gcount() : int istream:gcount(); 读空(指定一个大的数量)缓冲区函数ignore() : istream,解释EOF定义和应用,【例9.4】 ignore()和gcount()函数使用。,9.3 标准设备的输入/输出,输出流成员函数声明: ostream /刷新一个输出流,用于cout和clog,C+允许用户重载插入和提取运算符“”,,【例9.6】输出字符串地址。,9.4 文件的输入与输出,本节中文件指的是磁盘文件。C+根据文件(file)内容的数据格式,可分为两类:二进制文件和文本文件。文本文件由字符序列组成,也称ASCII码文件,在文本文件中存取的最小信息单位为字符(character),而二进制文件中存取的最小信息单位为字节(Byte)。,9.4.1 文件的打开与关闭,9.4.2 文本文件的读写,9.4.3 二进制文件的读写,9.4.4 文件的随机访问,9.4.5 文件与对象,9.4.1 文件的打开与关闭,文件的使用步骤如下: 1说明一个文件流对象,这又被称为内部文件: ifstream ifile;/只输入用 ofstream ofile;/只输出用 fstream iofile;/既输入又输出用,9.4.1 文件的打开与关闭,2使用文件流对象的成员函数打开一个磁盘文件。这样在文件流对象和磁盘文件名之间建立联系。文件流中说明了三个打开文件的成员函数。 void ifstream:open(const char*,int =ios:in, int=filebuf: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);,9.4.1 文件的打开与关闭,三个文件流类都重载了一个带缺省参数的构造函数,功能与open函数一样: ifstream:ifstream(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),文件流对象值物理上就是指它的地址。 因此打开一个文件完整的程序为: fstream iofile(”myfile.txt”,ios:in|ios:out); if(!iofile) cout”不能打开文件:”myfile,txt”endl; exit(1); /失败退回操作系统,9.4.1 文件的打开与关闭,使用提取和插入运算符对文件进行读写操作,或使用成员函数进行读写,这在下一节中讨论。 关闭文件。三个文件流类各有一个关闭文件的成员函数 void ifstream:close(); void ofstream:close(); void fstream:close(); 使用很方便,如: iofile.close();,9.4.1 文件的打开与关闭,关闭文件时,系统把该文件相关联的文件缓冲区中的数据写到文件中,保证文件的完整,收回与该文件相关的内存空间,可供再分配,把磁盘文件名与文件流对象之间的关联断开,可防止误操作修改了磁盘文件。如又要对文件操作必须重新打开。 关闭文件并没有取消文件流对象,该文件流对象又可与其他磁盘文件建立联系。文件流对象在程序结束时,或它的生命期结束时,由析构函数撤消。它同时释放内部分配的预留缓冲区。,9.4.1 文件的打开与关闭,文件打开方式是在ios类中定义的,公有枚举成员: enum open_mode in=0x01, /打开文件用于输入操作(从文件读取),文件指针在文件头 out=0x02, /*打开文件用于写入文件。如文件不存在,则建立,但指定目 录必须存在,否则建立文件失败。如文件存在,未同时设 app,ate,in则文件清空*/ ate=0x04, /打开文件用于输入/输出,文件指针在文件尾,但新数据可写到任何位置 app=0x08, /打开文件用于输出,但从尾部添加,新数据只能添加在尾部 trunce=0x10, /打开文件,并清空它,以建立新文件 nocreate=0x20, /如文件存在则打开,不存在并不创建新文件 noreplace=0x40, /如文件不存在则创建,如文件存在则只能设为ate及app方式 binary=0x80 ; /以二进制方式打开文件 使用方法与格式控制符相同,9.4.2 文本文件的读写,这里讨论文本文件的顺序读写。顺序读写可用C+的提取运算符()和插入运算符()进行。 【例9.7】复制文件。 【例9.8】按行复制文本文件。 【例9.9】文本式数据文件的创建与读取数据。资源获取是由构造函数实现,而资源释放是由析构函数完成,9.4.3 二进制文件的读写,C+提供了对二进制文件进行读写的成员函数: istream /第一个参数指定输出对象的内存地址, /第二个参数指定插入的字节数, /函数从该地址开始将指定数量的字节插入输入输出流,9.4.3 二进制文件的读写,读函数并不能知道文件是否结束,可用状态函数int ios:eof()来判断文件是否结束。必须指出系统是根据当前操作的实际情况设置状态位,如需根据状态位来判断下一步的操作,必须在一次操作后立即去调取状态位,以判断本次操作是否有效。,【例9.10】创建二进制数据文件,以及数据文件的读取。这两项操作设计为成员函数。给出与【例9.9】不同的读写方式:,使用二进制文件,可以控制字节长度,读写数据时不会出现二义性,可靠性高。同时不知格式是无法读取的,保密性好。文件结束后,系统不会再读(见eofbit的说明),但程序不会自动停下来,所以要判断文件中是否已没有数据。如写完数据后没有关闭文件,直接开始读,则必须把文件定位指针移到文件头。如关闭文件后重新打开,文件定位指针就在文件头。,9.4.4 文件的随机访问,C+把每一个文件都看成一个有序的字节流,见图9.3.每一个文件或者以文件结束符(end of file marker)结束,或者在特定的字节号处结束。,当打开一个文件时,该文件就和某个流关联起来了。对文件进行读写实际上受到一个文件定位指针(file position pointer)的控制。 输入流的指针也称为读指针,每一次提取操作将从读指针当前所指位置开始,每次提取操作自动将读指针向文件尾移动。 输出流指针也称写指针,每一次插入操作将从写指针当前位置开始,每次插入操作自动将写指针向文件尾移动。,9.4.4 文件的随机访问,在C+中可以由程序移动文件指针,从而实现文件的随机访问,即可读写流中任意一段内容。一般文本文件很难准确定位,所以随机访问多用于二进制文件。 在ios类中说明了一个公有枚举类型: enum seek_dir beg=0, /文件开头 cur=1, /文件指针的当前位置 end=2 /文件结尾 ;,9.4.4 文件的随机访问,istream类中提供了如下三个成员函数: istream 表示将文件定位指针从文件尾向文件头方向移20个字节。 tellg()和seekg()往往配合使用。 指针不可移到文件头之前或文件尾之后。,9.4.4 文件的随机访问,ostream类也提供了三个成员函数管理文件定位指针,它们是: ostream 为了便于记忆,函数名中g是get的缩写,而p是put的缩写。对输入输出文件定位指针只有一个但函数有两组,这两组函数功能完全一样。,【例9.11】使用随机访问对【例9.10】进行改造。,9.4.5 文件与对象,在面向对象的程序设计中,信息总是放在对象的数据成员里。这些信息最终应该保存到文件中。当程序开始运行时,就要由打开的文件重新创建对象。在运行过程中,放在对象的数据成员里的信息得到利用和修改。运行结束时必须把这些信息重新保存到文件中,然后关闭文件。 磁盘文件打开时建立的内部文件流是在运行时动态分配的资源。在面向对象的C+程序设计中,文件应该在构造函数中打开,并创建对象;而在析构函数中保存和关闭文件,并撤销对象。这样,与动态安排的其他资源一样,当撤销对象时,能自动释放资源。特别在程序发生异常时,C+系统有异常处理机制,该机制要求动态分配的资源是在类对象中,这样C+保证退出异常点时资源得到完整的释放。 对文件而言,释放资源同时包括将对象中的信息再次存入磁盘文件。在程序运行过程中,应该将信息适时保存到相应的磁盘文件中,以免数据意外丢失。,*9.5 字符串流(内存流),可以把流的概念连接到字符串(string)上。串可以看作字符流。可以用输入输出操作来完成串流的操作。串流是与内存相关,所以也称内存流。类包括ostrstream、istrstream、strstream。参见图9.2。串流类对象可以保存字符,也可以保存整数、浮点数。串流类对象采用文本方式。 其构造函数常用下面几个: istrstream:istrstream(const char * str); istrstream:istrstream(const char * str,int); ostrstream:ostrstream(char *,int,int=ios:out); 其中第二个参数说明数组大小。例:以串流为信息源 char ch, str36=”This is a book.n”; istrstream input(str); inputch; /从输入设备(串)读入一个字符 coutchendl; /输出T,9.6 MFC中的文件处理,MFC中的文件系统,是广义的文件系统。先讨论MFC的文档/视结构(Document/view),再讨论序列化(Serialization)与永久保存。,9.6.1 文档/视结构,9.6.2 存档类序列化,9.6.1 文档/视结构,文档(document)指的是数据组合的抽象,它通常对应磁盘文件,也可以对应I/O端口(包括打印机、键盘)或一块内存空间(串流)。 同样的数据,我们可以用不同的方式来表示。把纯的数据放在文件中或数据库中。而把显示方式分离出来,可以让一份数据有多种不同的显示方式,程序中的数据表现称为“视” 。这样就可以分别考虑数据的保存文档,和数据的表现视。 MFC提供了一种应用程序框架,其核心就是文档/视结构。在三种最基本的MFC程序框架中有两种:多文档结构和单文档结构。MFC采用两个既相互独立又相互紧密联系的类来实现这一结构: 1文档类CDocument,它主要用于存取文档; 2视图类CView,它主要用于显示和打印文档,并支持与用户的交互。,9.6.1 文档/视结构,图9.4 文档/视有关系统,9.6.1 文档/视结构,文档类的含义非常广泛。包括复合文档。在多文档结构(MDI)中一个子窗口所掌握的数据也称为一个文档。文档就是数据,CDocument就可以简单地理解为负责处理数据的类。在MFC编程时,我们应该把所有要处理的从外部获得的数据全部放在文档类及其派生类的对象中。CDocument类是一个预先编好的类,只是提供了一个外壳或者讲框架,程序员可以在Document中建立实际要用的数据格式及其管理方法。最常用的方法当然是派生出自己的文档类(CMyDocument类)。,9.6.1 文档/视结构,与文档类相配合的视类(CView)是文档的第一线,负责与使用者接触。文档和视是数据的两个方面,文档是体,视是面(表现)。数据的处理在文档中进行,它使用的是字节、整数、浮点数等数据,链表、顺序表和树、图等数据结构。而数据的表现视使用的是绘图工具:如绘图域、画笔、调色板等等。CView是为数据的表现而设计的。 View还负责程序与用户之间的交互。用户对数据的编辑、修改,对程序下达工作指令都要依赖窗口上的鼠标与键盘操作才能完成,这些信息由View接受后再传给Document(参见图9.4)。,9.6.1 文档/视结构,文档/视结构中,MFC类已经把一个应用程序所需的“数据处理与显示”的函数空壳都设计好了,这些函数都是虚函数,这样用户可在自己的派生类(CMyDocument和CMyView)中重编它们(多态)。有关档案(存档类CArchive,在下一小节讨论)的读写操作在文档中的Serialize()函数中进行,而有关视图窗口的操作在视类中的OnDraw或OnPaint函数中进行。所以在MFC的编程中,用户主要的工作是编写文档中的数据获得、数据保存和数据处理,视中的OnDraw和OnView函数。,9.6.2 存档类序列化,存档类(CArchive类)不是CObject的派生类,它提供运行时对象模式支持。Serialize()函数的参数是存档类CArchive对象的引用。CArchive类对象是在永久性对象(磁盘文件,CFile类对象)和非永久性对象(内存对象,如文档类对象)之间充当一个过渡角色。负责按一定的顺序和格式在两者之间进行存取。文件一般为二进制格式文件。而内存对象可以是简单数据变量,也可以是C+对象或CObject派生类对象。参见图9.5。,9.6.2 存档类序列化,MFC的存储功能被称为序列化(Serialization),CArchive对象从字面上看是档案,实际上是一个内存缓冲区。对文件的操作如果改为对CArichive对象的操作,速度要快的多,Serialize()操作的对象就是CArchive类对象。 函数CObject:Serialize是一个虚函数。改写时先调用它。要使CObject派生类真正有可序列化(Serializable)的功能,必须具备下列条件: 1由CObject派生出来,以保证有运行时类型识别(RTTL,Runtime Type Identification)、动态生成(Dynamic Creation)等机能。 2 改写Serialize虚函数,使它能适当地把类成员变量写入档案。 3 要加一个缺省的构造函数(无参)。MFC往往必须先动态生成存档类对象,而且是在无任何参数下生成对象。 4类声明必须包含一些必要的宏。,9.6.2 存档类序列化,通常在MFC程序中,由CWinApp:OnFileSaveAs()消息处理函数,打开一个对话框提示输入一个文件名,并创建一个该文件的CFile对象,然后把CFile对象绑定到一个CArchive对象上,最后调用文档类的Serialize()成员函数由参数引用CArchive对象。 CArichive对象与内存对象之间数据流的流动方向可用成员函数IsStoring()或IsLoading()来判断当前的数据流动方向。当打开文档时,IsStoring()返回false,IsLoading()返回true。当保存文档时,返回值相反。这可避免在程序中出现按实际数据流动方向相反操作的异常。,9.7 图书馆流通管理系统设计输出/输入流的应用,本节中,为图书馆流通管理系统中的各种类重载提取和插入运算符,通过文件流将数据保存到磁盘文件。 首先要为各对象类重载提取和插入运算符,它们都重载为这些类的友元函数。,一共有五种重载的提取和插入运算符。其它各类都很简单,直接输出输入各数据项就可以了。重点是读者类 。,读者类除了输出、输入基本信息,还有所借书链表,并且链表的长度对不同对象是不同的。当从文件读入数据重构对象时,要先获得读者所借书总数(rd.Counter)。并且先将这个数目读入局部变量count中,控制读入数据的数量,而重构的读者对象的所借书总数(rd.Counter)由构造函数赋值0,每次读入一项数据,由AddBook插入读者对象的所借书链表,而读者对象的所借书总数(rd.Counter)由AddBook函数自动增加。,9.7 图书馆流通管理系统设计输出/输入流的应用,重载读者类提取运算符,重建对象: istream ,9.7 图书馆流通管理系统设计输出/输入流的应用,重载读者类插入符,写入文件: ostream ,9.7 图书馆流通管理系统设计输出/输入流的应用,下面给双向链表模板类重载提取和插入运算符。 templateostream ,9.7 图书馆流通管理系统设计输出/输入流的应用,templateistream ,class Library /封装图书馆流通业务的类 /其它数据成员 ofstream itemFileOut; /文件流对象,保存可借阅书籍数据 ifstream itemFileIn; /文件流对象,读入可借阅书籍数据 ofstream magFileOut; /文件流对象,保存可借阅杂志数据 ifstream magFileIn; /文件流对象,读入可借阅杂志数据 ofstream readerFileOut; /文件流对象,保存读者数据 ifstream readerFileIn; /文件流对象,读入读者数据 ofstream managerFileOut; /文件流对象,保存管理员数据 ifstream managerFileIn; /文件流对象,读入管理员数据 ofstream loanFileOut; /文件流对象,保存借阅信息数据 ifstream loanFileIn; /文件流对象,读入借阅信息数据,图书馆类对象是整个流体系运行的源头,因此为图书馆类添加一组输入文件流对象,一组输出文件流对象,添加保存信息和读入信息的函数。,public: /其它函数成员 void SaveInfo(); /保存图书馆信息 void OpenInfo(); /读入图书馆信息 /以下在修改款目后分别保存和读入分类信息 void Saveitem(); void Openitem(); ;,void Library:SaveInfo() itemFileOut.open(“item.txt“); /打开各输出文件流 magFileOut.open(“mag.txt“); readerFileOut.open(“reader.txt“); loanFileOut.open(“loan.txt“); managerFileOut.open(“manager.txt“);,链表存入文件的意思是把链表的数据域存入文件,采用对应链表类中重载的插入运算符“”。,9.7 图书馆流通管理系统设计输出/输入流的应用,itemFileOutitemNumnitem; /向各文件存入相应链表结点个数及整个链表 magFileOutmagNumnmag; readerFileOutreaderNumnreader; loanFileOutloanNumnloan; managerFileOutmanagerNumnmanager; itemFileOut.close(); /关闭输出文件流 magFileOut.close(); readerFileOut.close(); loanFileOut.close(); managerFileOut.close(); 该函数将信息分类存入不同文件方便了信息的增删和修改,9.7 图书馆流通管理系统设计输出/输入流的应用,void Library:OpenInfo() itemFileIn.open(“item.txt“); /打开各输入文件流 itemFileInitemNumitem; /读入链表结点个数及并建立整个链表对象 magFileInmagNummag; readerFileInreaderNumreader; loanFileInloanNumloan; managerFileInmanagerNummanager; itemFileIn.close(); /关闭输入文件流 ,建立链表对象的意思是用文件中存放的各结点数据域重新生成链表对象的所有结点,采用对应链表类中重载的“”。,9.7 图书馆流通管理系统设计输出/输入流的应用,图书馆流通管理系统的设计到此结束。在本教材的电子文档中有完整的控制台程序和采用MFC编制的软件,可供读者参考。,SaveInfo和OpenInfo都在Library:Run中调用,在Run运行开始时,询问是否读入原来的数据,若回答是,调用OpenInfo;否则继续。在主菜单选择0退出时,先询问是否保存数据,若回答是,调用SaveInfo保存数据,否则不保存,直接退出。,第九章 流类库和输入/输出,结束,谢谢!,9.2 输入输出的格式控制,访问x_flags的重载函数定义如下: inline long ios:flags() const return x_flags; /返回当前标志字 inline long ios:flags(long _l) /参数作为新的标志字,并返回原标志字 long _l0; _l0=x_flags; x_flags=_l; return _l0; inline long ios:setf(long _l,long _m) long _l0; _l0=x_flag; x_flags=(_l ,9.2 输入输出的格式控制,相关接口函数为(此类函数仅要求知道用法): inline int ios:width() constreturn x_width; /返回当前域宽 inline int ios:width(int _i) /把参数作为新的域宽,返回原域宽 int _i0; _i0=(int)x_width; x_width=_i; return _i0; inline char ios:fill() constreturn x_fill; /返回当前填充字符 inline char ios:fill(char _c) /参数作为新填充字符,返回原填充字符 char _c0; _c0=x_fill; x_fill=_c; return _c0; inline int ios:precision(int i) /参数作为新精度,返回原精度 int _i0; _i0=(int)x_presion; x_presion=_i; return _i0; inline int ios:precision() const return x_presion; /返回当前精度,9.2 输入输出的格式控制,【例9.1】整型数输出。 void main(void) int inum=255; cout”十进制方式”inumt; cout.flags(ios:oct|ios:showbase); /八进制带数制基数输出是前面加0,参数等效0x00a0 cout”八进制方式”inumt; cout.setf(ios:hex); /等效0x0040,因是或关系,仍带基数输出,格式为0x. cout”十六进制方式”inumendl;,程序输出:十进制方式255 八进制方式0377 十六进制方式0xff,9.2 输入输出的格式控制,【例9.2】浮点数输出。 void main() double fnum=31.415926535; cout”缺省域宽为:”cout.width()”位”n; cout”缺省精度为:”cout.precision()”位”n; cout”缺省表达方式:”funmn; /按值大小,自动决定定点还是科学数方式 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位科学数表达方式:”fnumendl;,其中floatfield为0x1800,是为了避免浮点数互相冲突的双重规定,所以是清除原浮点数第13和第14两位,再用新的一位去代替。,9.2 输入输出的格式控制,流操作子(setiosflags stream manipulator)可代替流格式控制成员函数。但绝大多数流操作子VC+不支持,其他用setiosflags(long)对应setf(long),unsetiosflags(long)对应unsetf(long)来实现。,cin,cout和clog都是缓冲流。对输出而言,仅当输出缓冲区满才将缓冲区中的信息输出,对输入而言,仅当输入一行结束,才开始从缓冲区中取数据,当希望把缓冲区中的信息立即输出,可用flush,加endl也有同样功能,回车并立即显示,不必等缓冲区满(endl清空缓冲区)。,读取状态的有关操作如下: inline int ios:rdstate() const return state; /读取状态字 inline int ios:bad() /返回非法操作位 return state /正常返回1,9.3 标准设备的输入/输出,【例9.3】提高输入的健壮性。 void main() char str256; int i; couti; /可输入非数字字符,下次再输入若干字符加数字串等进行检测 while(cin.fail() couti; cin.getline(str,256); /读空缓冲区 cout“请输入字符串“endl; cin.getline(str,255); cout“输入整数为:“iendl; cout“输入字符串为:“strendl; ,9.3 标准设备的输入/输出,用下面的函数返回最后一次提取的字符数量,包括回车 int istream:gcount() const return x_gcoutnt; 还有一个成员函数可用来读空(指定一个大的数量)缓冲区: istream 第一个参数为要提取的字符数量,缺省为1;第二个参数表示遇到该字符则结束,包括该结束字符,但对所提取的字符不保存不处理,作用是空读。第二个参数的缺省值EOF为文件结束标志。,在iostream.h中EOF定义为-1,在int get()函数中,读入输入流结束标志Ctrl+Z(Z)时,函数返回EOF,为了能表示EOF的“-1”值,返回类型为int。采用cin.eof()函数,当前所读为EOF则返回非零,函数自身未从流中读取。,9.3 标准设备的输入/输出,【例9.4】ignore()和gcount()函数使用。 void main() char str255; int i,n; cout“输入字符“endl; i=cin.get(); /请输入Z,一旦输入Z全部结束,不能输入其它 coutendl; n=cin.rdstate(); /读取状态字 cout“状态字为:”nendl; /状态字为1,流结束 cout“当输入字符时,取得的是:“iendl; /输入Z时,返回EOF,即-1 if(n=0) cin.ignore(255,n); /清除多余的字符和回车符 cin.clear(0); / A 使流恢复正常 cout“输入字符串1:“endl; cin.getline(str,255);,9.3 标准设备的输入/输出,coutendl; cout“状态字为:“cin.rdstate()endl; i=cin.gcount(); cout“字符串为:“strt“读入字符数为:“it; cout“串长为:“strlen(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; 注意,若无两个A行,输入Z时,不再理会余下的所有输入。,9.3 标准设备的输入/输出,C+允许用户重载插入和提取运算符“”,以便用户利用标准的输入/输出流来输入/输出自定义的数据类型,实现对象的输入输出。重载必须保留原来的使用特性。重载可在用户定义类中,将重载的运算符的函数说明为该类的友元函数: friend istream 函数的返回值为对输入或输出流的引用,这是为了保证在cin和cout中可以连续使用“”或“”和“”或“”的左操作数;第二个参数为用户定义类的引用,作为右操作数。,【例9.5】用户定义的复数类型Complex的输入与输出。 class Complex /见【例5.7】,这里有省略,以节约篇幅 double Real,Image; public: Complex(double r=0.0, double i=0.0):Real(r),Image(i); friend ostream ,9.3 标准设备的输入/输出,istream,9.3 标准设备的输入/输出,putback()声明如下: stream 它将最后一次从输入流中得到的字符放回到输入流中。,9.3 标准设备的输入/输出,【例9.6】通常用输出数组名得到的是数组地址,但字符型数组(串)不同,输出的是数组内容。本例将字符指针强制转换为泛型指针输出字符串地址。,#include void main() char *string1=“欢迎学习C+程序设计课程!“; cout“串值是:“string1“n串地址是:“(void*)string1endl; ,istream ,putback()声明如下: stream 它将最后一次从输入流中得到的字符放回到输入流中。,9.3 标准设备的输入/输出,9.4.2 文本文件的读写,【例9.7】复制文件。 void main() ifstream sfile(“d:Ex9_6Ex9_6.cpp“); ofstream dfile(“e:Ex9_6.cpp“); /只能创建文件,不能建立子目录,如路径不存在则失败 char ch; if(!sfile)coutch) dfilech; sfile.close(); /如没有这两个关闭函数,析构函数也可关闭 dfile.close();,9.4.2 文本文件的读写,首先必须设置关闭跳过空白,因为提取(“”)运算符在缺省情况下是跳过空白(包括空格,制表,backspace和回车等)的,这样拷贝的文件会缺少一些字符。 第二,该程序能确定文件是否拷贝结束。流类成员函数和运算符全是返回本类型的引用,这里就是流文件对象自身,当文件结束时,返回NULL,这时不再拷贝,退出循环。 第三,拷贝是按字节进行的,效率很低,按字节传递开销极大,但该程序能正确拷贝任意类型的文件,不仅是文本文件(看作按字符),二进制文件(看作按字节)也一样可正确完成。如果是文本文件,我们可以按行进行拷贝。 第四,!sfile中的!是重载的运算符,在状态函数中重载,当该操作出现不正常状态,返回true。,【例9.8】按行复制文本文件。 void main() char filename256,buf100; fstream sfile,dfile; coutfilename; sfile.open(filename,ios:in|ios:nocreate); /打开一个已存在的文件 while(!sfile) coutfilename; sfile.open(filename,ios:in|ios:nocreate); coutfilename; /只能创建文件,不能建立子目录,如路径不存在则失败,dfile.open(filename,ios:out); if(!dfile)cou

温馨提示

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

评论

0/150

提交评论