(部分摘自《标准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模式强制将指针定位到文件尾,即使修改指针位置也无效.