流类库与输入输出 (一)

就像C语言一样,C++语言中也没有输入/输出语句。但C++编译系统带有一个面向对象的输入/输出软件包,它就是I/O流类库。流是I/O流类的中心概念。首先介绍流的概念,然后介绍流类库的结构和使用。对于流类库中类的详细说明及类成员的描述,请读者查阅所使用的编译系统的运行库参考手册。 
一、I/O流的概念
    使用VC++6.0在程序中实现I/O有几种方法:
     C运行库直接非缓冲的I/O
     ANSI C运行库流I/O
     控制台和端口直接I/O    
     Microsoft Foundation类库
     Microsoft I/O流类库
    其中I/O流类库对于缓冲的、格式化文本I/O是很有用的,它是C语言中I/O函数在面向对象的程序设计方法中的一个替换产品。
    我们简单介绍过,在C++中,将数据从一个对象到另一个对象的流动抽象为“流”。从流中获取数据的操作称为提取操作,向流中添加数据的操作称为插入操作,数据的输入与输出就是通过I/O流来实现的。这里,我们进一步介绍流的概念
    操作系统是将键盘、屏幕、打印机和通信端口作为扩充文件来处理的,而这种处理是通过操作系统的设备驱动程序来实现的。因此,从C++程序员的角度来看,这些设备与磁盘文件是等同的。I/O流类就是用来与这些扩充文件进行交互。
    当程序与外界环境进行信息交换时,存在着两个对象,一个是程序中的对象,另一个是文件对象。流是一种抽象,它负责在数据的生产者和数据的消费者之间建立联系,并管理数据的流动。程序建立一个流对象,并指定这个流对象与某个文件对象建立连接,程序操作流对象,流对象通过文件系统对所连接的文件对象产生作用。由于流对象是程序中的对象与文件对象进行交换的界面,对程序对象而言,文件对象有的特性,流对象也有,所以程序将流对象看作是文件对象的化身。
流所涉及的范围还远不止于此,凡是数据从一个地方传输到另一个地方的操作都是流的操作。像网络数据交换、进程数据交换等都是流操作。因此,一般意义下的读操作在流数据抽象中被称为(从流中)提取,写操作被称为(向流中)插入。
I/O流类列表
类    名     说      明 包含文件
抽象流基类
ios 流基类     iostream.h
输人流类
fstream           通用输入流类和其他输入流的基类 iostream.h
ifstream       输入文件流类   fstream.h
fstream_withassign         cin的输人流类 iostream.h
istrstream     输入字符串流类    strstrea.h
输出流类
ostream       通用输出流类和其他输出流的基类 iostream.h
ofstream       输出文件流类 fstream.h
ostream_withassign        cout、cerr和clog的输出漉类 iostream.h
ostrstream           输出字符串流类 strstrea.h
输入/输出流类
iostream         通用输入/输出流类和其他输入/输出流的基类 iostream.h
fstream       输入/输出文件流类   fstream.h
strstream        输人/输出字符串流类 strstrea.h
stdiostream        标准I/0文件的输入/输出类 stdiostr.h
流缓冲区类
streambuf       抽象流缓冲区基类 iostream.h
filebuf        磁盘文件的流缓冲区类 fstream.h
strstreambuf        字符串的流缓冲区类 strstrea.h
stdiobuf     标准I/O文件的流缓冲区类    stdiostr.h
预先定义的流初始化类
iostream-init   预先定义的流初始化类     iostream.h
 
  
二、输出流
    一个输出流对象是信息流动的目标,最重要的三个输出流是ostream,ofstream和 ostrstream。
    ostream类通过派生类ostream_withassign支持预先定义的流对象:
    &S226;cout标准输出
    &S226;cerr标准错误输出,没有缓冲,发送给它的内容立即被输出。
    &S226;clog类似于cerr,但是有缓冲,缓冲区满时被输出。
    从ostream和ostream_withassign构造的对象很少,通常用于预先定义的对象。 ostream类可以用于缓冲的或非缓冲的操作,最适合于顺序文本模式输出。

 ofstream类支持磁盘文件输出。如果你需要一个只输出的磁盘文件,可以构造一个 ofstream类的对象。在打开文件之前或之后可以指定ofstream对象接受二进制或文本模式数据。很多格式化选项和成员函数可以应用于ofstream对象,包括基类ios和ostream的所有功能。
如果在构造函数中指定一个文件名,当构造这个文件时该文件是自动打开的。否则,你可以在调用缺省构造函数之后使用open成员函数打开文件,或者在一个由文件指示符标识的打开文件基础上构造一个ofstream对象。 
(一)构造输出流对象
    如果你仅使用预先定义的cout、cerr或clog对象,就不需要构造一个输出流。例如,在本章之前的例题中,我们都是将信息输出到标准输出设备,使用的是cout。如果要使用文件流将信息输出到文件,便需要使用构造函数来建立流对象。
    构造输出文件流的常用方法如下:
    &S226;使用缺省构造函数,然后调用open成员函数,例如:
    ofstream myFile;    //声明一个静态输出文件流对象
myFile.open("filename",iosmode),    //打开文件,使流对象与文件建立联系
或:
    ofstream*  pmyFile=new ofstream;    //建立一个动态的输出文件流对象
    pmyFile->open("filename",iosmode);    //打开文件,使流对象与文件建立联系
    &S226;在调用构造函数时指定文件名和模式,
    ofstream myFile("filename",iosmode);
稍后会详细介绍open成员函数。 
(二)使用插入运算符和控制格式
    本小节介绍如何控制输出格式以及如何为自己的类建立插入运算符。插入(<<)运算符是所有标准C++数据类型预先设计的,用于传送字节到一个输出流对象。插入运算符与预先定义的操纵符一起工作,用来控制输出格式。
    1.输出宽度
    为了调整输出,可以通过在流中放人setw操纵符或调用width成员函数为每个项 (item)指定输出宽度。下面的例子在一列中以至少10个字符宽按右对齐方式输出数值:
例  使用width函数控制输出宽度
#i nclude
void main()
{
    double s[]={1.23,35.36,653.7,4358.24};
    for(int i=0;i<4;i++)
    {
  cout.width(10);
  cout<    }  
}
其输出结果是:
    1.23
   35.26
  653.7
 4358.24
    从程序的输出结果可以看到,在少于10个字符宽的数值前加入了引导空格。
空格是缺省的填充符,当输出的数据不能充满指定的宽度时,系统会自动以空格填充,也可以指定用别的字符来填充。使用fill成员函数可以为已经指定宽度的域设置填充字符的值。为了用星号填充数值列,我们可以将上例中的for循环修改如下:
for(int i=0;i<4;i++)    
    {
    cout.width(10);
    cout.fill("*");
    cout<    }
其输出结果如下:
 *******1.23
 ******35.26
 *****653.7
 ****4358.24
如果要为同一行中输出的不同数据项分别指定宽度,可以使用setw操纵符.
例 使用setw操纵符指定宽度
#i nclude 
#i nclude 
void main() 
{
 double s[]={1,23,35.36,653.7,4358.24};
 char *names[]={"Zoot","Jimmy","Al","Stan"};
 for (int i=0;i<4;i++)
  cout<}
width成员函数在iostream.h中说明了,如果带参量使用setw或任何其他操纵符,就必须包括iomanip.h。在输出中,字符串输出在宽度为6的域中,整数输出在宽度为10的域中,运行结果如下:
Zoot      1.23
Jimmy     35.36
    Al    653.7 
  Stan   4358.24
    setw和width都不截断数值。如果数值位超过了指定宽度,则显示全部值,当然还要遵守该流的精度设置。setw和width仅影响紧随其后的域,在一个域输出完后域宽度恢复成它的缺省值(必要的宽度)。但其他流格式选项保持有效直到发生改变。

   2.对齐方式
输出流缺省为右对齐文本,为了在前面的例子中左对齐姓名和右对齐数值,要将程序修改如下:
例   设置对齐方式
#i nclude 
#i nclude 
void main() 
{
 double s[]={1.23,35.36,653.7,4358.24};
 char *names[]={"Zoot","Jimmy","Al","Stan"};
 for (int i=0;i<4;i++)
  cout<   <   <   <}
其输出结果如下:
Zoot       1.23
Jimmy      35.36
Al          653.7 
Stan      4358.24
    这个程序中,是通过使用带参数的setiosflags操纵符来设置左对齐,参数是los::left枚举器。该枚举器定义在ios类中,因此引用时必须包括ios::前缀。这里需要用resetiosflags操纵符关闭左对齐标志。setiosflags不同于width和setw,它的影响是持久的,直到用resetiosflags重新恢复缺省值时为止。
    setiosflags的参数是该流的格式标志值,这个值由如下位掩码(ios枚举器)指定,并可用位或OR(|)运算符进行组合:
    ios::skipws  在输人中跳过空白。    
    ios::left  左对齐值,用填充字符填充右边。
    ios::right  右对齐值;用填充字符填充左边(缺省对齐方式)。
    ios::internal  在指定任何引导标记或基之后增加填充字符。
    ios::dec  以基10(十进制)格式化数值(缺省进制)。
    ios::oct  以基8(八进制)格式化数值。
    ios::hex  以基16(十六进制)格式化数值。
    ios::showbase  以C++编译器能读的格式显示数值常量。
    ios::showpoint  对浮点数值显示小数点和尾部的0。
    ios::uppercase  对于十六进制数值显示大写字母A到F,对于科学格式显示大写字母E。
    ios::showpos  对于正数显示正号(+)。
    ios::scientific  以科学格式显示浮点数值。
    ios::fixed  以定点格式显示浮点数值。
    ios::unitbuf  导致在每次插入之后ostream::osfx刷新该流。缺省地,cerr是缓冲的单元。
    ios::stdio  导致在每次插入之后ostream::osfx刷新该流的stdout和stderr。
    3.精度
    浮点数输出精度的缺省值是6,例如,数3466.9768显示为3466.98。为了改变精度,可以使用setprecision操纵符,该操纵符有两个标志,ios::fixed和los::scientific。如果设置了ios::fixed,该数输出为3466.976800;如果设置了ios::scientific,该数输出为 3.4669773+003。为了以1位有效数字显示浮点数,将前述程序修改如下:
例   控制输出精度 
#i nclude 
#i nclude 
void main() 
{
 double s[]={1.23,35.36,653.7,4358.24};
 char* names[]={"Zoot","Jimmy","Al","Stan"};
 for(int i=0;i<4;i++)
  cout<  <  <  <}
该程序的输出结果如下:
Zoot         1
Jimmy      4e+001
Al          7e+002 
Stan        5e+003
如果要删除科学标记,需要在for循环之前插入语句: cout<Zoot        1.2
Jimmy         35.4
Al            653.7 
Stan        4358.2
如果改变ios::fixed为ios::scientific,该程序的输出结果为:
Zoot      1.2e+000
Jimmy      3.5e+001
Al          6.5e+002 
Stan        4.4e+003
    同样,该程序在小数点后输出了一位数字,这表明如果设置了ios::fixed或 ios::scientific,则精度值确定了小数点之后的小数位数。如果都未设置,则精度值确定了总的有效位数。可以用resetiosflags操纵符清除这些标志。
    4.进制
dec、oct和hex操纵符设置输入和输出的缺省进制,例如,若将hex操纵符插入到输出流中,则以十六进制格式输出。如果ios::uppercase(缺省)标志已清除,该数值以a到f的数字显示;否则,以大写方式显示。缺省的进制是dec(十进制)。

你可能感兴趣的:(C++)