C++:IO标志位
(部分摘自《标准C++输入输出流与本地化》)
1. 状态标志.
1). 每个流对象都维护一个状态变量标记流状态(成功或失败),该变量类型是iostate(实际上是ios_base定义的位域类型),状态变量的不同二进制位用来标记不同状态,共有三个状态标志:
状态标志 |
作用 |
所占bit |
failbit |
出现可挽回的非致命错误 |
1 |
badbit |
出现不可挽回的致命错误 |
2 |
eofbit |
到达文件尾 |
3 |
goodbit |
没有错误 |
不占bit |
2). 函数
函数 |
作用 |
bool fail() |
若failbit位被置为1,返回true |
bool bad() |
若badbit位被置为1,返回true |
bool eof() |
若eofbit位被置为1,返回true |
bool good() |
若failbit,badbit,eofbit位全为0,返回true |
iostate rdstate() const |
获取当前流状态变量 |
void clear (iostate state = goodbit) |
重设流状态为state,并覆盖原有状态,默认为ios:goodbit |
void setstate (iostate state) |
在原有状态基础上添加state状态,其实是clear(rdstate()|state) |
2. 格式标志.
1). 除状态变量外,每一个流对象还维护一个fmtflags类型(与iostate类似)的格式变量,用来标记输入输出格式,格式标志有:
位组 |
格式标志 |
作用 |
默认值 |
所占bit |
|
skipws |
使用输入操作符时跳过空白字符 |
设置 |
1 |
|
unitbuf |
每次操作后刷新缓冲区 |
Cerr设置,其他对象不设置 |
2 |
|
uppercase |
字母采用大写 |
不设置 |
3 |
|
showbase |
输出整数时加上进制前缀 |
未设置 |
4 |
|
showpoint |
按精度输出浮点数(不够补0) |
未设置 |
5 |
|
showpos |
输出非负数时加‘+’ |
未设置 |
6 |
adjustfield |
left |
加入指定字符使输出左对齐 |
right |
7 |
right |
加入指定字符使输出右对齐 |
8 |
||
Internal |
在符号和数值中间插入指定字符 |
9 |
||
basefield |
dec |
10进制输入/输出 |
dec |
10 |
oct |
8进制输入/输出 |
11 |
||
hex |
16进制输入/输出 |
12 |
||
floatfield |
scientific |
浮点数按科学计数法输出 |
无,由浮点数量级决定 |
13 |
fixed |
浮点数按小数输出 |
14 |
||
|
boolalpha |
以字母格式输入和输出布尔值 |
未设置 |
15 |
(位组:有些标志位相互排斥,相互排斥的标记位属于同一位组,以便于对同一位组的标记位复位)
2). 函数
fmtflags flags() const |
获取当前格式变量 |
fmtflags flags (fmtflags fmtfl) |
将格式变量设为fmtfl,并返回之前的格式变量 |
fmtflags setf (fmtflags fmtfl) |
在原来格式基础上附加fmtfl,相当于flags(fmtfl|flags()). |
fmtflags setf (fmtflags fmtfl, fmtflags mask); |
将位组mask所包含的标记位清零,并置为fmtfl对应标记位的值,相当于flags((fmtfl&mask)|(flags()&~mask)) |
void unsetf (fmtflags mask) |
清除位组mask的格式标记位 |
streamsize width() const; |
获取当前域宽度 |
streamsize width (streamsize wide); |
设置域宽度为wide |
streamsize precision() const; |
获取当前精度 |
streamsize precision (streamsize prec); |
设置精度为prec |
char fill() const; |
获取当前的填充字符 |
char fill (char fillch) |
设置输出宽度不满域宽时的填充字符为fillch,默认为空格 |
注:在使用setf设置属于某一位组的标记位时,需要提供位组作为第二个参数来将其他互斥的标记位复位,否则可能会出现设置无效的现象.
3). 使用2)的函数可以设置输入输出的格式,标准库还提供了"操纵符"(类似于函数)使得格式化输入输出更加方便,将操纵符作为<<和>>的右操作数使用可以直接设置输入输出格式,使用这些操纵符需要加头文件<iomanip>操纵符有:
操纵符 |
影响 |
用途 |
等价表示 |
flush |
O |
刷新流缓冲区 |
o.flush() |
endl |
O |
插入换行符并刷新缓冲区 |
o.put(widen(‘\n’)); o.flush(); |
ends |
O |
插入串结束符 |
o.out(o.widen((‘\0’)); |
ws |
I |
抽取空白字符 |
|
boolalpha |
I/O |
设置bool型的输入输出格式 |
io.setf(ios_base::boolalpha) |
noboolalpha |
I/O |
复位上述标志 |
io.unsetf(ios_base::boolalpha) |
showbase |
O |
设置用于整数前缀的标志 |
o.setf(ios_base::showbase) |
noshowbase |
O |
复位上述标志 |
o.unsetf(ios_base::showbase) |
showpos |
O |
为非负整数设置产生’+’的标志 |
o.setf(ios_base::showpos) |
noshowpos |
O |
复位上述标志 |
o.unsetf(ios_base::showpos) |
showpoint |
O |
按精度输出浮点数(不够补0) |
o.setf(ios_base::showpoint) |
noshowpoint |
O |
复位上述标志 |
o.unsetf(ios_base::showpoint) |
skipws |
I |
设置跳过空白字符的标志 |
i.setf(ios_base::skipws) |
noskipws |
I |
复位上述标志 |
i.unsetf(ios_base::skipws) |
uppercase |
O |
大写输出字母 |
o.setf(ios_base::uppercase) |
nouppercase |
O |
复位上述标志 |
o.unsetf(ios_base::uppercase) |
unitbuf |
O |
设置每次格式化输出后刷新输出的标志 |
o.setf(ios_base::unitbuf) |
nounitbuf |
O |
复位上述标志 |
o.unsetf(ios_base::unitbuf) |
internal |
O |
设置在指定内部节点填充字符的标志 |
o.setf(ios_base::interbal,ios_base::adjustfield) |
left |
O |
设置左对齐标志 |
o.setf(ios_base::left,ios_base::adjustfield) |
right |
O |
设置右对齐标志 |
o.setf(ios_base::right,ios_base::adjustfield) |
dec |
I/O |
按十进制转换整数 |
io.setf(ios_base::dec,ios_base::basefield) |
hex |
I/O |
按十六进制转换整数 |
io.setf(ios_base::hex,ios_base::basefield) |
oct |
I/O |
按八进制转换整数 |
io.setf(ios_base::oct,ios_base::basefield) |
fixed |
O |
设置浮点数按定点表示标志 |
o.setf(ios_base::fixed,ios_base::floatfield) |
scientific |
O |
设置浮点数按科学表示法表示标志 |
o.setf(ios_base::scientific,ios_base::floatfield) |
setiosflags(ios_base::fmtflags mask) |
I/O |
根据mask设置格式标志 |
io.setf(ios_base::fmtflags mask) |
setiosflags(ios_base::fmtflags mask) |
I/O |
根据mask清除格式标志 |
io.unsetf(ios_base::fmtflags mask) |
setbase(int base) |
I/O |
为整数表示设置基数 |
io.setf(base==8?ios_base::oct:base==10?ios_base::dec:base==16?ios_base::hex:ios_base::fmtflags(0),ios_base::basefield) |
setfill(char c) |
I/O |
设置填充字符 |
io.fill(c) |
setprecision(int n) |
O |
设置精度 |
io.precision(n) |
setw(int n) |
I/O |
设置最小字宽 |
io.width(n) |
4). 正如以上所展示的,操纵符分为带参数和不带参数的,不带参数的操纵符本质上是具有特定参数和返回值类型的函数指针,带参数的操纵符本质上是重载了移位运算符的对象.
自定义不带参数的操纵符,可以像这样:
ios_base& boolalpha(ios_base& strm){ strm.setf(ios_base::boolaplha); return strm; } //ios_base是所有io流类的基类
自定义带参数的操纵符,可以像这样:
class width{ public: explicit width(unsigned int i):i_(0){} private: unsigned int i_; template<class charT,class Traits> friend base_ostream<char T,Traits>& operator<<(basic_ostream<charT,Traits>&ib,const width&w){ ib.width(w.i_); return ib; }
关于自定义操纵符的具体细节,详见《标准C++输入输出流与本地化》3.2
3. 文件打开方式标志
1). 使用文件流类型时,可以在构造函数或open函数中指定打开方式,参数是ios_base::openmode类型(和iostate和fmtflags类似),以下是用于指定文件打开方式的标记位:
名称 |
作用 |
所占bit |
app |
向文件尾增加数据 |
1 |
ate |
从文件尾部开始 |
2 |
binary |
以二进制方式读写 |
3 |
in |
以读方式打开文件 |
4 |
out |
以写方式打开文件 |
5 |
trunc |
清除文件内容(默认标志) |
6 |
2). 可以使用|同时按多个模式打开文件,但并不是所有的打开方式都可以组合,下表是合法的组合:
打开方式 |
作用 |
+ate标志 |
+binary标志 |
in in|trunc |
只读方式打开文件 只读方式打开文件设文件长度为0 |
初始文件位置指针在文件尾部 |
抑制转换 |
out out|trunc |
只写方式打开文件 只写方式打开文件并设文件长度为0 |
初始文件位置指针在文件尾部 |
抑制转换 |
out|app |
追加,尽在文件尾写入 |
初始文件位置指针在文件尾部 |
抑制转换 |
in|out |
读写均可 |
初始文件位置指针在文件尾部 |
抑制转换 |
int|out|trunc |
读写均可并设文件长度为0 |
初始文件位置指针在文件尾部 |
抑制转换 |
3). 其他注意事项
1''. 输出文件流默认打开方式为ios_base::out|ios_base::trunc,输入文件流默认打开方式为ios_base::in|ios_base::trunc,也就是说,对于单项文件流trunc标志位是默认设置的,但双向文件流默认打开方式为ios_base:in|ios_base::out,默认不设置trunc标志位
2''. ate(ate-end)和app,都是将文件指针定位在文件尾,不同之处在于,ate模式允许修改文件指针位置,app模式强制将指针定位到文件尾,即使修改指针位置也无效.