流和缓冲区
C++程序把输入和输出看作字节流.输入时,程序从输入流中抽取字节;输出时,程序将字节插入到输出流中.输入流中的字节可能来自键盘/硬盘/程序. 输出流中的字节可以流向屏幕/打印机/硬盘/程序.换句话说,流充当了程序和流源(流的来源)或流目标之间的桥梁.C++程序处理输出的方式将独立于其去向,因此管理输入分:
○ 将流与输入去向的程序关联起来
○ 将流与文件链接起来.
换句话说,输入流需要两个链接,每端各一个.文件端链接来源,程序段链接将流的输出部分转存到程序中; 同样对输出流的管理包括将输出流连接到程序以及将输出目标与流关联起来;
通常使用缓冲区可以更高效地处理输入输出.缓冲区是用作中介的内存块,将信息从设备传输到程序或从程序传输给设备的临时存储工具.
缓冲方法从磁盘上读取大量信息,讲这些信息存在缓冲区中,然后每次从缓冲区里读取一个字节,因为从内存中读取单个字节的速度非常快.所以这种方法更快更方便.达到缓冲区尾部之后程序将从磁盘上读取另一块数据.输出时程序首先填满缓冲区.然后把成块数据传给硬盘,并清空缓冲区,已被下一批输出使用.这被称为刷新缓冲区(flushing the buffer).
流,缓冲区和iostream文件
○ streambuf类维缓冲区提供内存,并提供了用于填充缓冲区,访问缓冲区内容,刷新缓冲区和管理缓冲区内存的类方法.
○ ios_base 类表示流的一般特征,如是否可读取,是二进制流还是文本流等;
○ ios类基于ios_base,其中包括了一个指向streambuf对象的指针成员;
○ ostream类是从iios类派而来的, 提供了输出的方法;
○ istream 类也是从ios类派来的,提供了输入方法;
○ iostream类是基于istream和ostream类的 因此继承了输入输出方法;
一些ostream方法
除了大家喜闻乐见的方法之外,ostream类提供了put()方法和write()方法.前者用于显示字符.后者用于显示字符串.
最初,put()方法原型如下:
ostream & put(char)
;
当前标准被模板化,以适用于wchar_t:
cout.put('W')
;
还可以将数值类型参数(如int)用于put,这样:
cout.put(65) // 输出A
cout.put(66.3) //转为66 输出B
write()方法显示整个字符串,模板原型如下:
basic_ostream<charT,traits>&write(const char_type* s,streamsize n)
第一个参数提供了要显示的字符串的地址,第二个参数指出要显示多少个字符串.
下面是一个及其智障的示例:
需要注意的是,write()方法并不会在遇到空字符的时候自动停止打印.而是只打印指定数目的字符.即使超出了字符的边界.
刷新输出缓冲区
在屏幕输出时,程序不必等到缓冲区被填满.列如,将换行符发送到缓冲区之后.将刷新缓冲区.多数C++实现都会在输入即将发生的时候刷新缓冲区.
可以手动控制刷新缓冲区: 控制符flush刷新缓冲区,而控制符endl刷新缓冲区并插入一个换行符.
其实控制符也是函数 可以直接调用flush()来刷新缓冲区:
flush(cout);
用cout进行格式化
### 1.修改显示时使用的计数系统:
ostream类是从ios类派生而来的.而后者是从ios_base派生来的.ios_base类里都是描述格式状态的信息.例如,一个类成员中某些位决定了使用的技术系统,而另一个成员决定了字段宽度.通过使用控制符(manipulator),可以控制显示整数时使用的计数系统.比如控制字段宽度,和小数尾数.
要控制整数以十进制,十六进制,八进制.可以使用dec,hex和oct控制符.
如hex(cout) 或 cout<< hex
将其技术系统格式状态设置为16进制;
下面是一个比较智障的栗子
### 2.调整字段宽度
在上个代码示例中,输出各列没有对齐,可以使用width函数将长度不同的数字放到宽度相同的字段中:
int width();
int width(int i);
第一种格式返回字段宽度的当前设置,第二种格式将宽度设置为i个空格,并返回以前的字段宽度值,且width方法只影响将显示的下一个项目.然后字段宽度将恢复为默认,下面是个书上的例子:
上诉输出中,值在字段中右对齐,右对齐时空格被插入到值的左侧,cout通过加入空格来填满整个字段,用来填充的字符叫做填充字符(fill chararcter),并且右对齐是默认的;w的值为0是因为cout.width(30)返回的是以前的字段宽度,而不是刚设置的值.
### 3.填充字符
默认使用空格填充字段中未被使用的部分,可以用fill()成员来改变填充字符,而且新的填充字段将一直有效,直到更改他为止,用星号填充:cout.fill('*')
### 4.设置浮点数的显示精度
浮点数精度的函数取决于输出模式.在默认模式下,他指的是显示的总位数.在定点模式和科学模式下,精度指的是小数点后面的位数.C++默认精度为6; 将精度设置为2: cout.precision(2)
### 5.打印末尾的0和小数点
下面的函数调用使cout显示末尾的小数点:cout.setf(ios_base::showpoint)
;showpoint是ios_base类中定义的类级静态常量;
### 6.setf()
ios_base类有一个受保护的数据成员,其中的各位(标记) ,像开关一样分别控制着格式化的各个方面,打开开关称为设置标记,并将相应位设为1.而setf()函数提供了一种调整标记的途径:
setf()有俩原型.第一个:
fmtflags setf(fmtflags);
fmtflags是bitmask类的typedef,用于存储标记格式;ios_base定义了代表位值的常量:
○ ios_base::boolalpha: 输入和输出bool值,可以为true或false;
○ ios_base::showbase: 对于输出,使用C++基数前缀 0 0x
○ ios_base::showpoint: 显示末尾的小数点
○ ios_base::uppercase: 对于十六进制输出 使用大写字符E表示法
○ ios_base::showpos: 在整数前面加上+
|
|
第二个seft()原型接受两个参数,并返回以前的设置:
fmtflags setf(fmtflags, fmtflags);
函数的这种格式用于设置由多位控制的格式选项; 第一参数和以前一样,也是一个包含了所需设置的fmtlages值.第二参数指出要清除第一个参数中的哪些位;
setf()函数是ios_base类的一个成员函数;由于这个类是ostream的基类,因此可以使用cout来调用该函数:
ios_base::fmtflags old = cout.setf(ios::left, ios::adjustfield)
要恢复之前的可以:
cou.setf(old,ios::adjustfield);
书上的例子:
## 6.iomanip
如果嫌前面那些麻烦的话,头文件iomanip中提供了一些其他控制符,他们能提供前面的部分服务.setprecision(),setfill() 和 setw(); setprecision()控制符接受一个指定精度的整数参数; setfill()控制符接受一个指定填充字符的char参数;setw()控制符接受一个指定字段宽度的整数参数;并且他们都能通过cout链接起来;
书上的例子: