资源描述
第九章第九章 流类库和输入流类库和输入/ /输出输出本章的最主要目的就是把对象保存到磁盘文件中并从本章的最主要目的就是把对象保存到磁盘文件中并从磁盘文件重建对象。当然磁盘文件重建对象。当然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 输入输入/输出流类派生体系输出流类派生体系iosstreambufistreamostreamistream_withassigniostreamostream_withassigniostream_withassign指针指针9.1 C+的基本流类体系的基本流类体系iostreamfstreamstrstreamstdiostreamiosistreamifstrstreamistream_withassignifstreamstreambuffilebufstrstreambufstdiobufiostream_initostreamofstreamostream_withassign ostrstream图图9.2 输入输入/输出流类层次输出流类层次streambuf是一个独立的是一个独立的类,只是类,只是ios有一个保护访有一个保护访问限制的指针指向它。问限制的指针指向它。streambuf的作用是管理的作用是管理一个流的缓冲区。一个流的缓冲区。ios提供了对流进行格式化提供了对流进行格式化输入输出和错误处理的成输入输出和错误处理的成员函数。所有派生都是公员函数。所有派生都是公有派生。有派生。istream类提供完类提供完成成提取(输入)提取(输入)操作的成操作的成员函数,而员函数,而ostream类提供类提供完成完成插入(输出)插入(输出)操作的操作的成员函数。成员函数。iostream类是类是前两者的组合。前两者的组合。9.1 C+的基本流类体系的基本流类体系在流类库中,最重要的两部分功能为在流类库中,最重要的两部分功能为标准输入标准输入/ /输出输出(standard input/outputstandard input/output)和)和文件处理文件处理。 在在C+C+的流类库中定义了四个全局流对象:的流类库中定义了四个全局流对象:cincin,coutcout,cerrcerr和和clogclog。可以完成人机交互的功能。可以完成人机交互的功能。 cin标准输入流对象,键盘为其对应的标准设备。标准输入流对象,键盘为其对应的标准设备。 cout标准输出流对象,显示器为标准设备。标准输出流对象,显示器为标准设备。 cerr和和clog标准错误输出流,输出设备是显示器。标准错误输出流,输出设备是显示器。 其中其中cin、cout和和clog是带缓冲区的,缓冲区由是带缓冲区的,缓冲区由streambuf类对象来管理。而类对象来管理。而cerr为非缓冲区流,一旦为非缓冲区流,一旦错误发生立即显示。错误发生立即显示。 要使用这四个功能,必须包含要使用这四个功能,必须包含文件。文件。 9.1 C+的基本流类体系的基本流类体系提取运算符提取运算符“”(stream_extraction operator)和和插入运算符插入运算符“”(stream_insertion operator),),执行输入执行输入/输出操作。输出操作。 “提取提取”的含义是指输入操作,可看作从流中提的含义是指输入操作,可看作从流中提取一个字符序列。取一个字符序列。 “插入插入”的含义是指输出操作,可看作向流中插的含义是指输出操作,可看作向流中插入一个字符序列。入一个字符序列。 文件处理完成永久保存的功能。在文件处理完成永久保存的功能。在VC+VC+的的MFCMFC编编程中采用了序列化(程中采用了序列化(SerializationSerialization)。)。 9.2 输入输出的格式控制输入输出的格式控制enum skipws=0 x0001,/跳过输入中的空白字符跳过输入中的空白字符 left=0 x0002, /输出左对齐输出左对齐 right=0 x0004,/输出右对齐输出右对齐 internal=0 x0008,/在输出符号或数制字符后填充在输出符号或数制字符后填充 dec=0 x0010,/在输入输出时将数据按十进制处理在输入输出时将数据按十进制处理 oct=0 x0020,/在输入输出时将数据按八进制处理在输入输出时将数据按八进制处理 hex=0 x0040,/在输入输出时将数据按十六进制处理在输入输出时将数据按十六进制处理 showbase=0 x0080,/在输出时带有表示数制基的字符在输出时带有表示数制基的字符 C+在类在类ios中提供格式化输入输出。这些格式中提供格式化输入输出。这些格式是对所有文本方式的输入输出流均适用。格式是对所有文本方式的输入输出流均适用。格式控制符定义为公有的无名的枚举类型:控制符定义为公有的无名的枚举类型:9.2 输入输出的格式控制输入输出的格式控制showpoint=0 x0100, /输出浮点数时输出浮点数时,必定带小数点必定带小数点 uppercase=0 x0200,/输出十六进制输出十六进制,用大写用大写 showpos=0 x0400,/输出正数时输出正数时,加加”+”号号 scientific=0 x0800,/科学数方式输出浮点数科学数方式输出浮点数 fixed=0 x1000,/定点数方式输出实数定点数方式输出实数 unitbuf=0 x2000,/插入后插入后,立即刷新流立即刷新流 stdio=0 x4000 /插入后插入后,立即刷新立即刷新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.4159279位科学数表达方式位科学数表达方式: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=0 x00, /流正常流正常 eofbit=0 x01, /输入流结束忽略后继提取操作;或文件结束已无数据可取输入流结束忽略后继提取操作;或文件结束已无数据可取 failbit=0 x02, /最近的最近的I/O操作失败操作失败,流可恢复流可恢复 badbit=0 x04, /最近的最近的I/O操作非法操作非法,流可恢复流可恢复 hardfail=0 x08 / I/O出现致命错误出现致命错误,流不可恢复流不可恢复,VC+不支持不支持 9.3 9.3 标准设备的输入标准设备的输入/ /输出输出点击查看点击查看读取状态的有关操作读取状态的有关操作【例【例9.3】提高输入的健壮性。输入时需要故提高输入的健壮性。输入时需要故意输错,以测试健壮性。意输错,以测试健壮性。9.3 标准设备的输入标准设备的输入/ /输出输出全面介绍输入输出流中的成员函数全面介绍输入输出流中的成员函数输入流成员函数声明:输入流成员函数声明:字符输入:字符输入:istream&istream:get(char &); istream&istream:get(unsigned char &); istream&istream:get(signed char &);提取一个字符提取一个字符,放在字符型变量中放在字符型变量中9.3 标准设备的输入标准设备的输入/ /输出输出字符串输入:字符串输入:istream&istream:get(char *,int,char=n);istream&istream:get(unsigned char *,int,char=n); istream&istream:get(signed char *,int,char=n); istream&istream:getline(char *,int,char=n); istream&istream:getline(unsigned char *,int,char=n); istream&istream:getline(signed char *,int,char=n); 提取的串放在第一个参数为开始地址的存储区(不查边界);第二提取的串放在第一个参数为开始地址的存储区(不查边界);第二个参数为至多提取的字符个数(指定为个参数为至多提取的字符个数(指定为n,最多取,最多取n-1个,再加一个个,再加一个字符串结束符);第三个参数为结束字符,遇此字符则结束,缺省字符串结束符);第三个参数为结束字符,遇此字符则结束,缺省为回车换行符为回车换行符。get系列函数要求单独提取结束字符。系列函数要求单独提取结束字符。getline提取字符串时如遇到提取字符串时如遇到指定结束符则提取该结束符,但不保存在串中。指定结束符则提取该结束符,但不保存在串中。这两个函数都会在这两个函数都会在提取的一系列字符后加一个串结束符,返回值为对象本身(提取的一系列字符后加一个串结束符,返回值为对象本身(*this)。)。 9.3 标准设备的输入标准设备的输入/ /输出输出返回最后一次提取的字符数量返回最后一次提取的字符数量,包括回车的包括回车的函数函数gcount() :int istream:gcount(); 读空(指定一个大的数量)缓冲区读空(指定一个大的数量)缓冲区函数函数ignore() :istream&istream:ignore(int=1,int=EOF);解释解释EOF定义和应用定义和应用【例【例9.4】 ignore()和和gcount()函数使用。函数使用。9.3 标准设备的输入标准设备的输入/ /输出输出输出流成员函数声明:输出流成员函数声明:ostream&ostream:put(char); /输出参数字符输出参数字符ostream&ostream:put(unsigned char);ostream&ostream:put(signed char);ostream&ostream:flush(); /刷新一个输出流刷新一个输出流,用于用于cout和和clogC+允许用户允许用户重载插入和提取运算符重载插入和提取运算符“”,【例【例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函数一样:函数一样:i f s t r e a m : : i f s t r e a m ( c o n s t 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”)和插入运算符()和插入运算符(ch; /从输入设备从输入设备(串串)读入一个字符读入一个字符coutch(istream& is, Reader& rd) Item it; Magazine mg; int type,count; isrd.Namerd.Positionrd.Agerd.Codecount; /A 读入读者基本信息读入读者基本信息 for( int i=0; itype; /先读入所借书的类别先读入所借书的类别(书本书本or杂志杂志) if(type) /如果是杂志如果是杂志 ismg; /读入一个杂志信息读入一个杂志信息 rd.AddBook(mg); /将杂志添加到读者所借书将杂志添加到读者所借书 else /书籍书籍 isit; /读入一个书籍信息读入一个书籍信息 rd.AddBook(it); /将书籍添加到读者所借书将书籍添加到读者所借书 return is; 9.7 9.7 图书馆流通管理系统设计图书馆流通管理系统设计输出输出/ /输入流的应用输入流的应用重载读者类插入符,写入文件:重载读者类插入符,写入文件:ostream& operator(ostream& os, Reader& rd) osrd.Name rd.Position rd.Age rd.Code rd.Countern; /输出读者基本信息输出读者基本信息 Book* p = rd.items; while(p) /输出读者所借书输出读者所借书 osGetType()GetType() os*(Magazine*)p; /基类指针基类指针转换转换为派生类指针输出对象为派生类指针输出对象 else osNext; return os; 9.7 9.7 图书馆流通管理系统设计图书馆流通管理系统设计输出输出/ /输入流的应用输入流的应用下面给双向链表模板类重载提取和插入运算符。下面给双向链表模板类重载提取和插入运算符。templateostream& operator(ostream& os, DblList &dlist) /重载插入运算符,链表重载插入运算符,链表存入文件存入文件 DblNode *tempP; int len = dlist.Length(); oslenrlink; while(tempP!=dlist.head) /循环输出链表各结点数据域循环输出链表各结点数据域 osInfo; /这里使用前面重载的五种这里使用前面重载的五种“rlink; return os; 9.7 9.7 图书馆流通管理系统设计图书馆流通管理系统设计输出输出/ /输入流的应用输入流的应用templateistream& operator(istream& is, DblList &dlist) /重载提取运算符,由文件重载提取运算符,由文件重构链表重构链表 int len; T tt; /结点数据域变量结点数据域变量 islen; /先读入链表长度先读入链表长度 for(int i=0;itt; /读入结点数据读入结点数据 /这里使用前面重载的五种这里使用前面重载的五种“”之一,对应类型之一,对应类型T dlist.Insert(tt); /插入链表,即建立一个新结点插入链表,即建立一个新结点 return is; 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 9.7 图书馆流通管理系统设计图书馆流通管理系统设计输出输出/ /输入流的应用输入流的应用 itemFileOutitemNumnitem; /向各文件存入相应链表结点个数及整个链表向各文件存入相应链表结点个数及整个链表 magFileOutmagNumnmag; readerFileOutreaderNumnreader; loanFileOutloanNumnloan; managerFileOutmanagerNumnitemNumitem; /读入链表结点个数及并建立整个链表对象读入链表结点个数及并建立整个链表对象 magFileInmagNummag; readerFileInreaderNumreader; loanFileInloanNumloan; managerFileInmanagerNummanager; itemFileIn.close(); /关闭输入文件流关闭输入文件流 建立链表对象的意思是用文件中存放的各结点数据域重新生建立链表对象的意思是用文件中存放的各结点数据域重新生成链表对象的所有结点,采用对应链表类中重载的成链表对象的所有结点,采用对应链表类中重载的“”。 9.7 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&_m)|(x_flags&(_m); return _l0; /第一个参数为增加的控制第一个参数为增加的控制,第二个参数表示取代原来哪几位第二个参数表示取代原来哪几位inline long ios:setf(long _l) /增加控制增加控制(多项多项) long _l0; _l0=x_flags; x_flags|=_l; return _l0; inline long ios:unsetf(long _l) /清除指定位上的控制清除指定位上的控制 long _l0; _l0=x_flags; x_flags &=(_l); return _l0; 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,参数等效参数等效0 x00a0 cout”八进制方式八进制方式”inumt; cout.setf(ios:hex); /等效等效0 x0040,因是或关系因是或关系,仍带基数输出仍带基数输出,格式为格式为0 x. cout”十六进制方式十六进制方式”inumendl;程序输出:程序输出:十进制方式十进制方式255 八进制方式八进制方式0377 十六进制方式十六进制方式0 xff9.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为为0 x1800,是,是为了避免浮点数互相冲突的为了避免浮点数互相冲突的双重规定,所以是双重规定,所以是清除原浮清除原浮点数第点数第13和第和第14两位两位,再用,再用新的一位去代替新的一位去代替。9.2 输入输出的格式控制输入输出的格式控制流操作子(流操作子(setiosflags stream manipulator)可代替流格式)可代替流格式控制成员函数。控制成员函数。但绝大多数流操作子但绝大多数流操作子VC+不支持,其他用不支持,其他用setiosflags(long)对应对应setf(long),unsetiosflags(long)对应对应unsetf(long)来实现。来实现。操作符操作符含义含义boolapha把把true和和false表示为字符串表示为字符串*noboolalpha把把true和和false表示为表示为0、1showbase产生前缀,指示数值的进制基数产生前缀,指示数值的进制基数*noshowbase不产生进制基数前缀不产生进制基数前缀showpoint总是显示小数点总是显示小数点*noshowpoint只有当小数部分存在是才显示小数点只有当小数部分存在是才显示小数点操作符操作符含义含义showpos在非负数值中显示在非负数值中显示+*noshowpos在非负数值中不显示在非负数值中不显示+*skipws输入操作符跳过空白字符输入操作符跳过空白字符noskipws输入操作符不跳过空白字符输入操作符不跳过空白字符uppercase在十六进制下显示在十六进制下显示0X,科学计数法中显示,科学计数法中显示E*nouppercase在十六进制下显示在十六进制下显示0 x,科学计数法中显示,科学计数法中显示e*dec以十进制显示以十进制显示(VC支持支持)hex以十六进制显示以十六进制显示(VC支持支持)oct以八进制显示以八进制显示(VC支持支持)left将填充字符加到数值的右边将填充字符加到数值的右边right将填充字符加到数值的左边将填充字符加到数值的左边internal将填充字符加到符号和数值的中间将填充字符加到符号和数值的中间*fixed以小数形式显示浮点数以小数形式显示浮点数scientific以科学计数法形式显示浮点数以科学计数法形式显示浮点数flush 刷新刷新ostream缓冲区缓冲区(VC支持支持)操作符操作符含义含义ends插入字符串结束符,刷新插入字符串结束符,刷新ostream缓冲区缓冲区(VC支持支持)endl 插入换行符,然后刷新插入换行符,然后刷新ostream缓冲区缓冲区(VC支持支持)ws“吃掉吃掉”空白字符空白字符(VC支持支持)/以下这些参数化的流操作子要求以下这些参数化的流操作子要求#includesetfill(ch)用用ch填充空白字符填充空白字符(VC支持支持)setprecision(n)将浮点精度设置为将浮点精度设置为n (VC支持支持)setw(n) 按照按照w个字符来读或者写个字符来读或者写(VC支持支持)setbase(b)以进制基数以进制基数b为输出整数值为输出整数值(VC支持支持)注:注:*表示缺省的流状态表示缺省的流状态cin,cout和和clog都是都是缓冲流缓冲流。对输出而言,仅当输出缓冲区满。对输出而言,仅当输出缓冲区满才将缓冲区中的信息输出,对输入而言,才将缓冲区中的信息输出,对输入而言,仅当输入一行结束,仅当输入一行结束,才开始从缓冲区中取数据才开始从缓冲区中取数据,当希望把缓冲区中的信息立即输出,当希望把缓冲区中的信息立即输出,可用可用flush,加,加endl也有同样功能,回车并立即显示,不必等缓也有同样功能,回车并立即显示,不必等缓冲区满(冲区满(endl清空缓冲区)。清空缓冲区)。 读取状态的有关操作如下:读取状态的有关操作如下:inline int ios:rdstate() const return state; /读取状态字读取状态字inline int ios:bad() /返回非法操作位返回非法操作位 return state & badbit;inline void ios:clear(int _i)/人工设置状态人工设置状态,可用来清状态可用来清状态 lock();state=_i;unlock(); inline int ios:eof() const return state&eofbit; /返回流结束位返回流结束位inline int ios:fail() const /返回操作非法和操作失败这两位返回操作非法和操作失败这两位 return state&(badbit|failbit); inline int ios:operator!() const return state&(badbit|failbit); /可用操作符可用操作符!()代替代替fail()inline int ios:good() constreturn state=0; /正常返回正常返回1 9.3 9.3 标准设备的输入标准设备的输入/ /输出输出【例【例9.3】提高输入的健壮性。】提高输入的健壮性。void main() char str256; int i; cout请输入整数请输入整数:i; /可输入非数字字符可输入非数字字符,下次再输入若干字符加数字串等进行检测下次再输入若干字符加数字串等进行检测 while(cin.fail() coutcin.rdstate()endl; /输出状态字输出状态字 cin.clear(0); /清状态字清状态字 cin.getline(str,255); /读空缓冲区读空缓冲区 cout输入错误输入错误,请重新输入整数请重新输入整数i; cin.getline(str,256); /读空缓冲区读空缓冲区 cout请输入字符串请输入字符串endl; cin.getline(str,255); cout输入整数为输入整数为:iendl; cout输入字符串为输入字符串为:strendl; 9.3 标准设备的输入标准设备的输入/ /输出输出用下面的函数返回最后一次提取的字符数量用下面的函数返回最后一次提取的字符数量,包括回车包括回车int istream:gcount() const return x_gcoutnt;还有一个成员函数可用来读空(指定一个大的数量)缓冲区:还有一个成员函数可用来读空(指定一个大的数量)缓冲区:istream&istream:ignore(int=1,int=EOF);第一个参数为要提取的字符数量,缺省为第一个参数为要提取的字符数量,缺省为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&operator(istream&,className&);friend ostream&operator”或或“”和和“”或或“”的左操作数;第二个参数为的左操作数;第二个参数为用户定义类的引用,作为右操作数。用户定义类的引用,作为右操作数。【例【例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&operator(istream&s,Complex&a); ;ostream&operator(ostream&s,const Complex &z) return s(z.Real,z.Image(istream&s,Complex &a) /格式为格式为d,(d),(d,d) double re=0,im=0; char c=0; sc; if(c=()/是否由括号开始是否由括号开始 srec; /实部实部 if(c=,) simc; /虚部虚部 if(c!=) s.clear(ios:failbit); /漏了括号给一个操作失败标志漏了括号给一个操作失败标志 else s.putback(c); /无括号,返回一个字符到输入缓冲区无括号,返回一个字符到输入缓冲区 sre; /实数实数 if(s)a=Complex(re,im); return s;9.3 9.3 标准设备的输入标准设备的输入/ /输出输出putback()声明如下:声明如下:stream&istream:putback(char);它将最后一次从输入流中得到的字它将最后一次从输入流中得到的字符放回到输入流中符放回到输入流中。9.3 标准设备的输入标准设备的输入/ /输出输出【例【例9.6】通常用输出数组名得到的是数组地址,但字符型】通常用输出数组名得到的是数组地址,但字符型数组(串)不同,输出的是数组内容。本例将字符指针强数组(串)不同,输出的是数组内容。本例将字符指针强制转换为泛型指针输出字符串地址。制转换为泛型指针输出字符串地址。#includevoid main() char *string1=欢迎学习欢迎学习C+程序设计课程!程序设计课程!; cout串值是:串值是:string1n串地址是:串地址是:(void*)string1(istream&s,Complex &a) /格式为格式为d,(d),(d,d) double re=0,im=0; char c=0; sc; if(c=() /是否由括号开始是否由括号开始 srec; /实部实部 if(c=,) simc; /虚部虚部 if(c!=) s.clear(ios:failbit); /漏了括号给一个操作失败标志漏了括号给一个操作失败标志 else s.putback(c); /无括号,返回一个字符到输入缓冲区无括号,返回一个字符到输入缓冲区 sre; /实数实数 if(s)a=Complex(re,im); return s;putback()声明如下:声明如下:stream&istream:putback(char);它将最后一次从输入流中得到的它将最后一次从输入流中得到的字符放回到输入流中字符放回到输入流中。9.3 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)cout不能打开源文件不能打开源文件: d:Ex9_6Ex9_6.cppendl; exit(1); if(!dfile)cout不能打开目标文件不能打开目标文件:e:Ex9_6.cpp ch) dfile”)运算符在)运算符在缺省情况下是跳过缺省情况下是跳过空白空白(包括空格,制表,(包括空格,制表,backspace和回和回车等)的,这样拷贝的文件会缺少一些字符。车等)的,这样拷贝的文件会缺少一些字符。第二第二,该程序能确定文件是否,该程序能确定文件是否拷贝结束拷贝结束。流类成员函数和运。流类成员函数和运算符全是返回本类型的引用,这里就是流文件对象自身,当算符全是返回本类型的引用,这里就是流文件对象自身,当文件结束时,返回文件结束时,返回NULL,这时不再拷贝,退出循环。,这时不再拷贝,退出循环。第三第三,拷贝是,拷贝是按字节进行按字节进行的,效率很低,按字节传递开销极的,效率很低,按字节传递开销极大,但该程序能正确拷贝任意类型的文件,不仅是文本文件大,但该程序能正确拷贝任意类型的文件,不仅是文本文件(看作按字符),二进制文件(看作按字节)也一样可正确(看作按字符),二进制文件(看作按字节)也一样可正确完成。如果是文本文件,我们可以按行进行拷贝。完成。如果是文本文件,我们可以按行进行拷贝。第四第四,!sfile中的!是重载的运算符,在状态函数中重载,中的!是重载的运算符,在状态函数中重载,当该操作出现不正常状态,返回当该操作出现不正常状态,返回true。【例【例9.8】按行复制文本文件】按行复制文本文件。void main() char
展开阅读全文