#include <iostream.h> class unsafe_ios { public: // exported types // stream status bits
enum io_state { goodbit = 0x00, // no bit set: all is ok eofbit = 0x01, // at end of file failbit = 0x02, // last I/O operation failed badbit = 0x04, // invalid operation attempted hardfail = 0x80 // unrecoverable error };
// stream operation mode enum open_mode { in = 0x01, // open for reading out = 0x02, // open for writing ate = 0x04, // seek to eof upon original open app = 0x08, // append mode: all additions at eof trunc = 0x10, // truncate file if already exists nocreate = 0x20, // open fails if file doesn't exist noreplace= 0x40 // open fails if file already exists };
// stream seek direction enum seek_dir { beg=0, cur=1, end=2 };
// formatting flags enum { skipws = 0x0001, // skip whitespace on input left = 0x0002, // left-adjust output right = 0x0004, // right-adjust output internal = 0x0008, // padding after sign or base indicator dec = 0x0010, // decimal conversion oct = 0x0020, // octal conversion hex = 0x0040, // hexidecimal conversion showbase = 0x0080, // use base indicator on output showpoint = 0x0100, // force decimal point (floating output) uppercase = 0x0200, // upper-case hex output showpos = 0x0400, // add '+' to positive integers scientific= 0x0800, // use 1.2345E2 floating notation fixed = 0x1000, // use 123.45 floating notation unitbuf = 0x2000, // flush all streams after insertion stdio = 0x4000 // flush stdout, stderr after insertion };
public: // exported functions // format-related functions long flags(); long flags(long bits); long setf(long setbits, long field); long setf(long setbits); long unsetf(long unsetbits); int width(); int width(int len); char fill(); char fill(char ch); int precision(int len); int precision(); int skip(int doskip); // obsolete // state-related functions int rdstate(); int eof(); int fail(); int bad(); int good(); void clear(int state=0); // other functions ostream* tie(ostream* tiedstream); ostream* tie(); streambuf* rdbuf(); static long bitalloc(); static int xalloc(); long & iword(int index); void* & pword(int index); static void sync_with_stdio(); public: // exported operator and conversion functions operator void* (); int operator ! (); public: // exported constructor, destructor unsafe_ios(streambuf* sbp); virtual ~unsafe_ios(); public: // exported data members static const long basefield; // dec | oct | hex static const long adjustfield; // left | right | internal static const long floatfield; // scientific | fixed protected: // protected function void init(streambuf* sbp); // protected constructor unsafe_ios(); void setstate (int); static void (*stdioflush)(); private: // private members to prevent copying unsafe_ios(unsafe_ios&); void operator= (unsafe_ios&); };
class ios : virtual public unsafe_ios, public stream_MT { public: // format-related functions long flags(); long flags(long); long setf(long setbits, long field); long setf(long); long unsetf(long); int width(); int width(int); char fill(); char fill(char); int precision(); int precision(int); // state-related functions int rdstate(); int eof(); int fail(); int bad(); int good(); void clear(int state =0); // other functions ostream* tie(); ostream* tie(ostream*); streambuf* rdbuf(); static long bitalloc(); static int xalloc(); long& iword(int); void* & pword(int); static void sync_with_stdio(); public: // exported operator and conversion functions operator void*(); int operator!(); public: // exported operator and conversion functions ios(streambuf* sbp); virtual ~ios(); protected: init(streambuf* sbp); ios(); setstate(int); static void (*stdioflush)(); protected: static stream_rmutex static_mutlock; static int mutex_init_count; private: ios(ios&); void operator=(ios&) ; };
// Predefined manipulators unsafe_ostream& endl(unsafe_ostream&); unsafe_ostream& ends(unsafe_ostream&); unsafe_ostream& flush(unsafe_ostream&); ostream& endl(ostream&); ostream& ends(ostream&); ostream& flush(ostream&); unsafe_ios& dec(unsafe_ios&); unsafe_ios& hex(unsafe_ios&); unsafe_ios& oct(unsafe_ios&); ios& dec(ios&); ios& hex(ios&); ios& oct(ios&); unsafe_istream& ws(unsafe_istream&); istream& ws(istream&);
类 ios 是所有流对象的一个虚拟基类。它提供流的基本状态和格式设置数据。定义了几个枚举和一个大的函数集合。下文中将对它们进行描述。
类 unsafe_ios 实现了此类的所有功能。类 ios 是一个“包装器”类,它围绕 unsafe_ios 的每个成员函数实施互斥锁以针对多个线程的访问提供保护。不过,使用受保护的类不能担保多线程安全性;有关使应用程序成为多线程安全的应用程序的更多信息,请参见《C++ Library Reference》中的第 4 章 "Using Classic iostream in a Multithreaded Environment"。
成员函数使用这些枚举跟踪流的错误状态。有关如何测试这些位的信息,另请参见下文中的“错误状态”部分。io_state 实际上是位的集合,如下所述:
此“位”实际上表示没有任何错误位,并且表示流处于良好状态。
当提取期间到达了文件末尾时通常会设置此位。它不是因为到达文件末尾的成功提取而设置的,而是因为在到达文件末尾时试图进一步提取而设置的。从这个意义上来讲,“文件末尾”是一个抽象概念,如与流关联的 streambuf 所定义。通常情况下,不会为输出流设置此位。
当尝试执行的提取或转换失败时(通常是因为意外字符)会设置此位。在清除此位之前,进一步尝试提取将失败,以阻止在不正确的输入后运行。通常情况下,在清除此位并处理意外输入后,流仍然可以使用并且提取可以继续进行。
此位表示对关联的 streambuf 的某项操作已失败。通常情况下,即使清除了此位,尝试进一步操作也不会成功。示例情况包括输出错误,或者在尝试执行输入操作时立即到达了文件末尾。
此位是为实现保留的,表示流无法进一步使用。通常情况下,它表示某种类型的硬件故障。无法通过任何可供公共访问的函数清除此位。
fstream(3CC4) 中在函数 open() 的描述部分下描述了这些枚举。
sbufpub(3CC4) 中在函数 seekoff() 的描述部分下描述了这些枚举。
成员函数使用匿名类型的这些枚举来控制输入和输出格式设置。请参见下文中的“格式控制”部分。
sbp 指向的 streambuf 将成为与正在构造的 ios 关联的 streambuf。指针不能为空。
过去,虚拟基类需要一个缺省的构造函数(一个没有参数的构造函数),因为过去无法将参数传递给虚拟基类的构造函数。因此,类 ios 具有一个缺省的构造函数和一个单独的接受指向 streambuf 的指针的初始化函数。缺省情况下,派生的类使用受保护的构造函数 ios() 并且调用初始化函数 init(streambuf*)。init 的参数指向要与正在构造的 ios 关联的 streambuf 并且不能为空。示例:
class istream : virtual public ios { ... }; istream::istream(streambuf* s) { ios::init(s); // ... }
复制构造函数和赋值运算符是专用的以防止复制 ios 对象,因为这类复制的影响不好确定。通常,您希望复制指向对象的指针或者传递对函数的引用。
有几个函数支持对错误状态位进行测试和调整,如下所述。
将流 s 的错误状态位作为 int 返回。
将其 int 参数存储为流 s 的错误状态。只应当从 rdstate 的返回值和/或 io_state 位的组合派生 state 的值。要仅清除流状态中的一位,请使用 s.clear(~ios::failbit & s.rdstate()); 之类的函数
如果错误状态为良好,也就是说,如果未设置任何位,则返回非零值。否则将返回零。具体而言,如果设置了 eofbit,则返回零。
如果设置了 eofbit,则返回非零值,否则将返回零。
如果设置了 failbit、badbit 或 hardfail 中的任何一个,则返回非零值,否则将返回零。
如果设置了 badbit 或 hardfail,则返回非零值,否则将返回零。
能够直接测试流的状态通常比较实用。因为典型的插入和提取运算符返回对流的引用,所以您可以测试运算的返回值。为允许此测试,定义了两个运算符。
您可以使用流到 void* 的显式转换或者在布尔上下文中使用流来测试其状态。如果设置了 failbit、badbit 或 hardfail 中的任何一个,则结果为 0。如果流处于良好或 eof 状态,则结果为非零指针。示例:
if( cout ) ... // next output will probably succeed if( cin >> x ) ... // input to x succeeded
此运算符提供以上测试的反转。如果设置了 failbit、badbit 或 hardfail 中的任何一个,则结果为非零值,否则结果为零。示例:
if( ! cout ) ... // output will not succeed if( ! (cin >> x) ) ... // input to x failed
ios 维护着一个格式状态,该格式状态由格式设置标志与 fill()、width() 和 precision() 这三个函数进行控制。格式设置标志是下文中描述的位的集合,声明为匿名类型的枚举。这些格式状态位保留为 long int 并且可以通过 flags() 函数的两个版本独立地进行操作。
格式设置标志可以独立于其他运算进行设置和清除。它们仅通过显式程序员操作进行更改。这些标志如下所述:
如果设置了此标志,有格式的提取器将跳过前导空格;否则,将不会跳过前导空格。此标志是缺省设置的,允许自由格式的输入文本。无格式的提取器不检查此标志。
这些标志控制在有格式运算期间如何插入填充。一次最多可以设置这三个标志中的一个。可以通过静态成员 ios::adjustfield 将这三个标志处理为一个单元。如果设置了 left,则会将值在其字段宽度中向左调整,这意味着将在右侧添加填充。如果设置了 right,则会将值在其字段宽度中向右调整,这意味着将在左侧添加填充。如果设置了 internal,则填充将添加在任何前导基或符号字段之后、值之前。缺省值(未设置任何标志)是 right。用于填充的填充字符缺省为空格字符,并且可以通过 fill 函数进行设置。填充量是由 width 函数设置的字段宽度决定的。另请参见 manip(3CC4)。
这些标志控制整数数据的转换基。一次最多可以设置这三个标志中的一个。可以通过静态成员 ios::basefield 将这三个标志处理为一个单元。如果设置了 dec,则转换以十进制(以 10 为基)执行;如果设置了 oct,则转换以八进制(以 8 为基)执行;如果设置了 hex,则转换以十六进制(以 16 为基)执行。如果未设置这些标志中的任何一个,则插入以十进制执行,并且提取将根据用于表示整数常量的 C++ 规则进行转换。也就是说,前导 "0x'' 或 "0X'' 将导致十六进制转换,前导 '0' 将导致八进制转换,前导 '1' 到 '9' 将导致为提取进行十进制转换。缺省设置是不设置这些位中的任何一个。还可以使用操纵符 dec、oct 和 hex 来设置转换基,如下文中的“预定义的操纵符”部分所述。
如果设置了此标志,则转换后的整数值的插入将采用用于表示 C++ 整数常量的形式。也就是说,八进制值将以前导 '0' 开头,十六进制值将以前导 "0x'' 或 "0X'' 开头。(请参见下文中的 "uppercase"。)缺省设置是不设置。
如果设置了此标志,则会向所插入的转换后正十进制值(包括浮点数)添加一个加号 ('+')。缺省设置是不设置。
如果设置了此标志,则当设置了 showbase 时在插入转换的十六进制值时将使用大写的 'X',并且将使用大写 'E' 进行浮点数转换。否则,将分别使用小写的 'x' 和 'e'。缺省设置是不设置。
这些标志控制在为插入转换浮点值时使用的转换类型。可以通过静态成员 ios::floatfield 将这两个标志处理为一个单元。进行转换时遵循的规则通常与用于 C stdio 函数 printf 的规则相同。(请参见 printf(3c)。)如果设置了 scientific,则将使用 'e' 格式。如果设置了 fixed,则将使用 'f' 格式。如果两者都没有设置,则将使用 'g' 格式。(另请参见上文中的 uppercase。)将使用由 width 设置的值(如果存在)作为 printf 字段宽度规范。将使用由 precision 设置的值(如果存在)作为 printf 精度规范。
如果设置了此标志,则尾随零或尾随小数点将显示在浮点值的转换中。缺省设置是截去尾随零或尾随小数点。
如果对输出流进行了缓冲,则当缓冲区填满时或者当显式对其进行刷新时将对缓冲区进行刷新。这可能会导致输出延迟,在程序崩溃的情况下还可能会导致输出丢失。流可以是无缓冲的,这消除了延迟和输出丢失,但代价是每个字符输出都需要一次系统调用。如果设置了 unitbuf,则将在每个完成的插入后刷新缓冲区。因此,Unit buffering 是一种折中方法,以比无缓冲输出更低的成本提供频繁的输出,并且在程序源代码中不需要额外的 flush 调用。具体而言,可以在代码中在选定的位置启用或禁用单元缓冲而不需要更改任何其他源代码。缺省情况下未设置此标志。
此标志将导致每次在流中进行插入后刷新 C stdio 文件 stdout 和 stderr。当标准文件上的 C stdio 与其他文件上的 iostreams 进行混合时,这可能比较有用。缺省情况下未设置此标志。
格式控制函数如下所述:
以 long 类型返回流 s 的当前格式设置标志。
使用 newflags 的 long 值替换流 s 中的所有格式设置标志。以 long 类型返回以前的格式设置标志。
将在流 s 的格式设置标志中设置在 long 值 newflags 中设置的每个位。其余的格式设置标志不受影响。以 long 类型返回以前的格式设置标志。注意,flags 函数替换所有标志位,而 setf 函数仅设置指定的那些位。此版本的 setf 最适合用于设置不属于组的一部分的标志。要设置一组标志中的一个,请参见下文中此函数的第二种形式。
在 long 值 field 中设置的位标记了将由 long 值 newflags 中的对应位替换的格式设置标志。返回指定标志的以前值。通常情况下,将使用常量 basefield、adjustfield 和 floatfield 中的一个作为 field 的值。示例-设置为左调整,输出一个值,并恢复以前的调整:
long oldadjust = cout.setf(ios::left, ios::adjustfield); cout << data; cout.setf(oldadjust, ios::adjustfield);
此方法可确保只设置了 adjustfield 位中的一位,并且可以方便地恢复以前的状态。使用零作为字段的新值将仅清除那些标志。示例-将整数转换基清除为缺省状态:
cout.setf(0, ios::basefield);
另请参见 manip3CC4 中的操纵符 (setiosflags) 和 resetiosflags。
将在流 s 的格式设置标志中取消设置在 long 值 newflags 中设置的每个位。其余的格式设置标志不受影响。以 long 类型返回以前的格式设置标志。注意,setf 函数设置对应的标志位,而 unsetf 函数则清除它们。另请参见 manip (3CC4) 中的 resetiosflags 操纵符。
返回流 s 的当前填充字符。填充字符用于将插入内容填充到指定的字符宽度。此发行版仅支持将单字节字符用于填充。请参见上文中针对 left、right 和 internal 的讨论。
将流 s 的填充字符设置为 newfill 并返回旧的填充字符。缺省填充字符为空格。另请参见 manip3CC4() 中的操纵符 setfill。
返回流 s 的当前“精度”格式状态。它控制在浮点数插入中转换的有效位数。请参见上文中针对 scientific 和 fixed 的讨论。
将流 s 的“精度”格式状态设置为 newprec 并返回旧值。缺省值为 6。另请参见 manip3CC4() 中的操纵符 setprecision。
返回流 s 的当前“字段宽度”格式状态。如果字段宽度为零,则插入器将仅插入表示所插入的值所需的字符。如果字段宽度大于所需的字符数,则字段将使用填充字符填充到指定的宽度,如上文所述。如果字段宽度小于所需的字符数,则将对宽度进行扩展。字段宽度表示最小字段宽度;不能使用它提供到最大字段宽度的截断。对于宽字符输出,宽度仍然是以字符为单位(而不是以字节为单位)测量的。
将流 s 的“字段宽度”格式状态设置为 newwidth 并返回旧值。缺省值为 0。在每次有格式的插入或提取后,字段宽度将自动重置为零。因此,对于需要字段宽度的每个操作,必须对其进行重置。另请参见 manip3CC4() 中的操纵符 setw。
对于可能需要其自己的格式标志和变量的派生类,可以提供用户定义的格式标志和变量。一旦为某个类分配了标志和变量,它们在程序的持续期间都将保留;几个独立的类可以无冲突地分配其自己的标志和变量。
此静态成员函数针对一个以前未分配的标志位集返回 long 值。然后,可以将该值用作标志,例如,在 setf 调用中针对特定于类的目的。最少有 16 个位可以用于分配。当没有位可用时,此函数返回零。
此静态成员函数将以前未使用的某个索引返回到 word 的数组中。word 足够大,可以包含 long 或 void*。然后,可以将该索引与函数 iword 或 ipword 一起使用以获取对保留的状态变量的引用。
当 i 是由 ios::xalloc 调用返回的索引值时,这些函数返回对用户为类 s 定义的第 i 个状态变量 (word) 的引用。函数 iword 返回类型为 long 的引用,函数 ipword 返回类型为 void* 的引用。注意:不要期望返回的引用会无限期地保持稳定。特别是对 xalloc() 的调用可能会导致以前的引用无效。
返回指向与流关联的 streambuf 的指针。这是流的构造的一部分,并且缓冲区类对象通常不会更改。给定一个流对象,可以使用此函数直接了解 streambuf 函数。
流可以“绑定”到一个 ostream,由 "tie" 流变量进行跟踪。每当某个流需要获得更多输入或刷新其输出时,如果存在绑定的流,将首先刷新绑定的流。例如,一开始就将 cin 绑定到 cout,以便在尝试新输入之前刷新未决的输出(例如提示)。此函数将流 s 的 tie 变量设置为输入参数 osp 指向的 ostream 并返回 tie 变量的旧值。序列
ostream* oldosp = s.tie(0); ... do something ... s.tie(oldosp);
将在执行某项工作时取消绑定某个流,然后恢复以前的绑定。
返回 "tie" 变量的当前值。(请参见上文。)
如果在同一个标准文件上执行 C stdio 和 C++ 流操作,则会发生同步问题。因为每种风格的 I/O 将有其自己的缓冲方式,所以 I/O 不会按程序的执行顺序进行。要解决此同步问题,请在对标准流 cin、cout、cerr 或 clog 执行任何 I/O 之前调用此静态函数。此函数将标准流重置为使用 stdiobuf。然后,通过 stdio 和流的 I/O 将是同步的。与仅使用缓冲的流 I/O 或仅使用缓冲的 stdio 相比,性能大幅降低。请参见 stdiobuf(3CC4)。注意:只有当对同一个标准输入、输出或错误文件执行 I/O 时才需要 sync_with_stdio。您可以毫无困难地在 stdin 上以排他方式使用 stdio 输入函数,在 cout 上以排他方式使用流输出函数。
操纵符可以明确地用作插入的或提取的对象,但实际上仅更改流的状态。有关更多信息,请参见 manip(3CC4)。预定义了多个与流一起使用的操纵符。
它们将流 s 的转换基设置为 10。
它们将流 s 的转换基设置为 8。
它们将流 s 的转换基设置为 16。
这从流 s 中提取并丢弃空格。请参见 istream(3CC4)。
向流 s 中插入一个换行符并刷新流。请参见 ostream(3CC4)。
向流 s 中插入一个空字符 ('\0') 以结束字符串。请参见 strstream(3CC4)。
刷新流 s。请参见 ostream(3CC4)。
当包括了 <manip.h> 时将有更多的操纵符可用。请参见 manip(3CC4)
printf (1) 、 filebuf (3CC4) 、 fstream (3CC4) 、 ios.intro (3CC4) 、 istream (3CC4) 、 manip (3CC4) 、 ostream (3CC4) 、 printf (3C) 、 sbufprot (3CC4) 、 sbufpub (3CC4) 、 ssbuf (3CC4) 、 stdiobuf (3CC4) 、 strstream (3CC4) 、 stream_locker (3CC4) 、 stream_MT (3CC4)
《C++ Library Reference》中的第 3 章 "The Classic iostream Library" 和第 4 章 "Using Classic iostreams in a Multithreaded Environment"。