C++程序设计湖南大学杜四春、银红霞第14章I/O流14.1C++流的概念14.2格式化I/O14.3检测流操作的错误14.4文件流14.5字符串流C++程序设计湖南大学杜四春、银红霞C语言中没有提供专门的输入输出语句,同样,C++语言中也没有专门的输入/输出(I/O)语句,C++中的I/O操作是通过一组标准I/O函数和I/O流来实现的。C++的标准I/O函数是从C语言继承而来的,同时对C语言的标准I/O函数进行了扩充。C++的I/O流不仅拥有标准I/O函数的功能,而且比标准I/O函数功能更强、更方便、更可靠。C++程序设计湖南大学杜四春、银红霞14.1C++流的概念在C++语言中,数据的输入和输出(简写为I/O)包括对标准输入设备键盘和标准输出设备显示器、对在外存磁盘上的文件和对内存中指定的字符串存储空间进行输入输出这三个方面。对标准输入设备和标准输出设备的输入输出简称为标准I/O,对在外存磁盘上文件的输入输出简称为文件I/O,对内存中指定的字符串存储空间的输入输出简称为串I/O。C++中把数据之间的传输操作称作流。在C++中,流既可以表示数据从内存传送到某个载体或设备中,即输出流;也可以表示数据从某个载体或设备传送到内存缓冲区变量中,即输入流。在进行I/O操作时,首先打开操作,使流和文件发生联系,建立联系后的文件才允许数据流入或流出,输入或输出结束后,使用关闭操作使文件与流断开联系。C++程序设计湖南大学杜四春、银红霞C++为实现数据的输入和输出定义了一个庞大的类库,它包括的类主要有ios,istream,ostream,iostream,ifstream,ofstream,fstream,istrstream,ostrstream,strstream等。其中ios为根基类,它直接派生四个类:输入流类istream、输出流类ostream、文件流基类fstreambase和字符串流基类strstreambase。输入文件流类同时继承了输入流类和文件流基类(当然对于根基类是间接继承),输出文件流类ofstream同时继承了输出流类和文件流基类,输入字符串流类istrstream同时继承了输入流类和字符串流基类,输出字符串流类ostrstream同时继承了输出流类和字符串流基类,输入输出流类iostream同时继承了输入流类和输出流类,输入输出文件流类fstream同时继承了输入输出流类和文件流基类,输入输出字符串流类strstream同时继承了输入输出流类和字符串流基类。C++程序设计湖南大学杜四春、银红霞C++系统中的I/O类库,其所有类被包含在iostream.h,fstream.h和strstrea.h这三个系统头文件中,各头文件包含的类如下:iostream.h包含有:ios,iostream,istream,ostream,iostream_withassign,istream_withassign,ostream_withassign等。fstream.h包含有:fstream,ifstream,ofstream和fstreambase,以及iostream.h中的所有类。strstrea.h包含有:strstream,istrstream,ostrstream和strstreambase,以及iostream.h中的所有类。C++程序设计湖南大学杜四春、银红霞在一个程序或一个编译单元(即一个程序文件)中当需要进行标准I/O操作时,则必须包含头文件iostream.h,当需要进行文件I/O操作时,则必须包含头文件fstream.h,同样,当需要进行串I/O操作时,则必须包含头文件strstrea.h。在一个程序或编译单元中包含一个头文件的命令格式为“#include头文件名”,当然若头文件是用户建立的,则头文件名的两侧不是使用尖括号,而是使用双引号。当系统编译一个C++文件对#include命令进行处理时,是把该命令中指定的文件中的全部内容嵌入到该命令的位置,然后再编译整个C++文件生成相应的目标代码文件。C++程序设计湖南大学杜四春、银红霞C++不仅定义有现成的I/O类库供用户使用,而且还为用户进行标准I/O操作定义了四个类对象,它们分别是cin,cout,cerr和clog,其中cin为istream_withassign流类的对象,代表标准输入设备键盘,也称为cin流或标准输入流,后三个为ostream_withassign流类的对象,cout代表标准输出设备显示器,也称为cout流或标准输出流,cerr和clog含义相同,均代表错误信息输出设备显示器。因此当进行键盘输入时使用cin流,当进行显示器输出时使用cout流,当进行错误信息输出时使用cerr或clog。C++程序设计湖南大学杜四春、银红霞C++的流通过重载运算符“”和“”执行输入和输出操作。输出操作是向流中插入一个字符序列,因此,在流操作中,将运算符“”称为插入运算符。输出操作是从流中提取一个字符序列,因此,将运算符“”称为提取运算符。1.cout在ostream输出流类中定义有对左移操作符重载的一组公用成员函数,函数的具体声明格式为:ostream&operator(简单类型标识符);C++程序设计湖南大学杜四春、银红霞简单类型标识符除了与在istream流类中声明右移操作符重载函数给出的所有简单类型标识符相同以外,还增加一个void*类型,用于输出任何指针(但不能是字符指针,因为它将被作为字符串处理,即输出所指向存储空间中保存的一个字符串)的值。由于左移操作符重载用于向流中输出表达式的值,所以又称为插入操作符。如当输出流是cout时,则就把表达式的值插入到显示器上,即输出到显示器显示出来。C++程序设计湖南大学杜四春、银红霞2.cin在istream输入流类中定义有对右移操作符重载的一组公用成员函数,函数的具体声明格式为:istream&operator(简单类型标识符&);简单类型标识符可以为char,signedchar,unsignedchar,short,unsignedshort,int,unsignedint,long,unsignedlong,float,double,longdouble,char*,signedchar*,unsignedchar*之中的任何一种,对于每一种类型都对应着一个右移操作符重载函数。由于右移操作符重载用于给变量输入数据的操作,所以又称为提取操作符,即从流中提取出数据赋给变量。C++程序设计湖南大学杜四春、银红霞3.cerrcerr类似标准错误文件。cerr与cout的差别在于:(1)cerr是不能重定向的;(2)cerr不能被缓冲,它的输出总是直接传达到标准输出设备上。错误信息是写到cerr的项。即使在各种其他输出语句中,如果使用下列语句,则错误信息“Error”总能保证在显示器上显示出来:cerr“Error”“\n”;C++程序设计湖南大学杜四春、银红霞4.clogclog是不能重定向的,但是可以被缓冲。在某些系统中,由于缓冲,使用clog代替cerr可以改进显示速度:clog“Error”“\n”;C++程序设计湖南大学杜四春、银红霞14.2格式化I/O14.2.1ios类中的枚举常量在根基类ios中定义有三个用户需要使用的枚举类型,由于它们是在公用成员部分定义的,所以其中的每个枚举类型常量在加上ios::前缀后都可以为本类成员函数和所有外部函数访问。在三个枚举类型中有一个无名枚举类型,其中定义的每个枚举常量都是用于设置控制输入输出格式的标志使用的。该枚举类型定义如下:enum{skipws,left,right,internal,dec,oct,hex,showbase,showpoint,uppercase,showpos,scientific,fixed,unitbuf,stdio};C++程序设计湖南大学杜四春、银红霞各枚举常量的含义如下:(1)skipws利用它设置对应标志后,从流中输入数据时跳过当前位置及后面的所有连续的空白字符,从第一个非空白字符起读数,否则不跳过空白字符。空格、制表符‘\t’、回车符‘\r’和换行符‘\n’统称为空白符。默认为设置。(2)left,right,internalleft在指定的域宽内按左对齐输出,right按右对齐输出,而internal使数值的符号按左对齐、数值本身按右对齐输出。域宽内剩余的字符位置用填充符填充。默认为right设置。在任一时刻只有一种有效。C++程序设计湖南大学杜四春、银红霞(3)dec,oct,hex设置dec对应标志后,使以后的数值按十进制输出,设置oct后按八进制输出,而设置hex后则按十六进制输出。默认为dec设置。(4)showbase设置对应标志后使数值输出的前面加上“基指示符”,八进制数的基指示符为数字0,十六进制数的基指示符为0x,十进制数没有基指示符。默认为不设置,即在数值输出的前面不加基指示符。(5)showpoint强制输出的浮点数中带有小数点和小数尾部的无效数字0。默认为不设置。C++程序设计湖南大学杜四春、银红霞(6)uppercase使输出的十六进制数和浮点数中使用的字母为大写。默认为不设置。即输出的十六进制数和浮点数中使用的字母为小写。(7)showpos使输出的正数前带有正号“+”。默认为不设置。即输出的正数前不带任何符号。(8)scientific,fixed进行scientific设置后使浮点数按科学表示法输出,进行fixed设置后使浮点数按定点表示法输出。只能任设其一。缺省时由系统根据输出的数值选用合适的表示输出。C++程序设计湖南大学杜四春、银红霞(9)unitbuf,stdio这两个常量很少使用,所以不予介绍。在ios中定义的第二个枚举类型为:enumopen_mode{in,out,ate,app,trunc,nocreate,noreplace,binany};其中的每个枚举常量规定一种文件打开的方式,在定义文件流对象和打开文件时使用。在ios中定义的第三个枚举类型为:enumseek_dir{beg,cur,end};其中的每个枚举常量用于对文件指针的定位操作上。C++程序设计湖南大学杜四春、银红霞14.2.2ios类中的成员函数ios类提供成员函数对流的状态进行检测和进行输入输出格式控制等操作,每个成员函数的声明格式如下:intbad();inteo();intfail();voidclear();charfill();charfill(charc);longflags();longflags(longf);intgood();intprecision();intrdstate();intprecision(intn);intwidth();longsetf(longf);intwidth(intw);longunsetf(longf);C++程序设计湖南大学杜四春、银红霞因为所有I/O流类都是ios的派生类,所以它们的对象都可以调用ios类中的成员函数和使用ios类中的格式化常量进行输入输出格式控制。下面以标准输出流对象cout为例说明输出的格式化控制。例14-1C++程序设计湖南大学杜四春、银红霞14.2.3格式控制操作符数据输入输出的格式控制还有更简便的形式,就是使用系统头文件iomanip.h中提供的操纵符。使用这些操纵符不需要调用成员函数,只要把它们作为插入操作符(个别作为提取操作符)的输出对象即可。这些操纵符及功能如下:decocthexwsendlendsflushsetiosflags(longf)resetiosflags(longf)setfill(intc)setprecision(intn)setw(intw)C++程序设计湖南大学杜四春、银红霞在上面的操纵符中,dec,oce,hex,endl,ends,flush和ws除了在iomanip.h中有定义外,在iostream.h