- IO 对象不可复制或赋值。这个要求有两层特别重要的含义。
- 正如在第九章看到的,只有支持复制的元素类型可以存储在 vector 或其他容器类型里。由于流对象不能复制,因此不能存储在 vector(或其他)容器中(即不存在存储流对象的 vector 或其他容器)。
- 第二个含义是:形参或返回类型也不能为流类型。如果需要传递或返回 IO 对象,则必须传递或返回指向该对象的指针或引用:
ofstream &print(ofstream&); // ok: takes a reference, no copy while (print(out2)) { /* ... */ } // ok: pass reference to out2
一般情况下,如果要传递 IO 对象以便对它进行读写,可用非 const 引用的方式传递这个流对象。对 IO 对象的读写会改变它的状态,因此引用必须是非 const 的。
- badbit 标志着系统级的故障,如无法恢复的读写错误。如果出现了这类错误,则该流通常就不能再继续使用了。如果出现的是可恢复的错误,如在希望获得数值型数据时输入了字符,此时则设置 failbit 标志,这种导致设置 failbit 的问题通常是可以修正的。eofbit 是在遇到文件结束符时设置的,此时同时还设置了 failbit。
-
常量 含义 failbit标记位的值 eofbit标记位的值 badbit标记位的值 转化为10进制 ios::failbit 输入(输出)流出现非致命错误,可挽回 1 0 0 4 ios::badbit 输入(输出)流出现致命错误,不可挽回 0 0 1 2 ios::eofbit 已经到达文件尾 0 1 0 1 ios::goodbit 流状态完全正常 0 0 0 0 -
cin.clear(ios::failbit);
使 得cin的流状态将按照ios::failbit所描述的样子进行设置:failbit标记位为1,eofbit标记位为0,badbit标记位为0。无 需担心goodbit标记位,failbit、eofbit、badbit任何一个为1,则goodbit为0。(goodbit是另一种流状态的表示方法)
cin.clear(ios::goodbit);
使得cin的流状态将按照ios::goodbit所描述的样子进行设置:failbit标记位为0,eofbit标记位为0,badbit标记位为0。此时goodbit标记位为1,从另一个角度表示cin的流状态正常。
因此clear() 函数作用是:将流状态设置成括号内参数所代表的状态,强制覆盖掉流的原状态。
再来分析一下setstate()函数:
与clear()函数不同,setstate()函数并不强制覆盖流的原状态,而是将括号内参数所代表的状态叠加到原始状态上。
比如,假设cin流状态初始正常:
cin.setstate (ios::failbit); //在cin流的原状态的基础上将failbit标记位置为1 cin.setstate (ios::eofbit); //在上一步结束的基础上,将cin流状态的eofbit标记位置为1
两条语句结束后,cin的faibit标记位和eofbit标记位均为1,badbit标记位为0
对比clear()函数的效果:
cin.clear (ios::failbit); //将cin的流状态置为ios::failbit所描述的状态 cin.clear (ios::eofbit); //将cin的流状态置为ios::eofbit所描述的状态
两条语句结束后,cin的eofbit标记位为1,而failbit标记位和badbit标记位为0
即使两种情况,在执行完各自的第一条语句后,cin的流状态情况相同,但当执行完第二条语句,本质区别就显露出来。
- 下面几种情况将导致缓冲区的内容被刷新,即写入到真实的输出设备或者文件:
- 程序正常结束。作为 main 返回工作的一部分,将清空所有输出缓冲区。
- 在一些不确定的时候,缓冲区可能已经满了,在这种情况下,缓冲区将会在写下一个值之前刷新。
- 用操纵符(第 1.2.2 节)显式地刷新缓冲区,例如行结束符 endl。
- 在每次输出操作执行完后,用 unitbuf 操作符设置流的内部状态,从而清空缓冲区。
- 可将输出流与输入流关联(tie)起来。在这种情况下,在读输入流时将刷新其关联的输出缓冲区。
- 我们的程序已经使用过 endl 操纵符,用于输出一个换行符并刷新缓冲区。除此之外,C++ 语言还提供了另外两个类似的操纵符。第一个经常使用的 flush,用于刷新流,但不在输出中添加任何字符。第二个则是比较少用的 ends,这个操纵符在缓冲区中插入空字符 null,然后后刷新它:
cout << "hi!" << flush; // flushes the buffer; adds no data cout << "hi!" << ends; // inserts a null, then flushes the buffer cout << "hi!" << endl; // inserts a newline, then flushes the buffer
- 如果需要刷新所有输出,最好使用 unitbuf 操纵符。这个操纵符在每次执行完写操作后都刷新流:
cout << unitbuf << "first" << " second" << nounitbuf;
等价于:cout << "first" << flush << " second" << flush;
nounitbuf 操纵符将流恢复为使用正常的、由系统管理的缓冲区刷新方式。 - fstream 对象一旦打开,就保持与指定的文件相关联。如果要把 fstream 对象与另一个不同的文件关联,则必须先关闭(close)现在的文件,然后打开(open)另一个文件:要点是在尝试打开新文件之前,必须先关闭当前的文件流。open 函数会检查流是否已经打开。如果已经打开,则设置内部状态,以指出发生了错误。接下来使用文件流的任何尝试都会失败。
- 关闭流(fstream)并不能改变流对象的内部状态。如果最后的读写操作失败了,对象的状态将保持为错误模式,直到执行 clear 操作重新恢复流的状态为止。调用 clear 后,就像重新创建了该对象一样。但是打开新的流(fstream)会重新恢复流的状态,例如:
void fstreamTest() { ifstream infile(__FILE__); if(!infile) { cout << "open " << __FILE__ << " failed." << endl; } cout << "open " << __FILE__ << " success." << endl; string line; while(getline(infile, line)) { cout << line << endl; } //infile.clear(); cout << "infile.rdstate() = " << infile.rdstate() << endl; //infile.rdstate() = 3 infile.close(); //必须要先关闭再打开,否则infile流状态会出错 cout << "infile.rdstate() = " << infile.rdstate() << endl; //infile.rdstate() = 3 infile.open(__FILE__); cout << "infile.rdstate() = " << infile.rdstate() << endl; //infile.rdstate() = 0 while(getline(infile, line)) { cout << line << endl; } infile.close(); }
-
in 打开文件做读操作 out 打开文件做写操作 app 在每次写之前找到文件尾 ate 打开文件后立即将文件定位在文件尾 trunc 打开文件时清空已存在的文件流/td> binary 以二进制模式进行 IO 操作
out、trunc 和 app 模式只能用于指定与 ofstream 或 fstream 对象关联的文件;in 模式只能用于指定与 ifstream 或 fstream 对象关联的文件。所有的文件都可以用 ate 或 binary 模式打开。ate 模式只在打开时有效:文件打开后将定位在文件尾。以 binary 模式打开的流则将文件以字节序列的形式处理,而不解释流中的字符。
默认时,与 ifstream 流对象关联的文件将以 in 模式打开,该模式允许文件做读的操作:与 ofstream 关联的文件则以 out 模式打开,使文件可写。以 out 模式打开的文件会被清空:丢弃该文件存储的所有数据。 - 模式是文件的属性而不是流的属性,每次打开文件时都会设置模式
ofstream outfile; // output mode set to out, "scratchpad" truncated outfile.open("scratchpad", ofstream::out); outfile.close(); // close outfile so we can rebind it // appends to file named "precious" outfile.open("precious", ofstream::app); outfile.close(); // output mode set by default, "out" truncated outfile.open("out");
-
out 打开文件做写操作,删除文件中已有的数据 out | app 打开文件做写操作,在文件尾写入 out | trunc 与 out 模式相同 in 打开文件做读操作 in | out 打开文件做读、写操作,并定位于文件开头处 in | out | trunc 打开文件做读、写操作,删除文件中已有的数据 - stringstream 对象的一个常见用法是,需要在多种数据类型之间实现自动格式化时使用该类类型。例如,有一个数值型数据集合,要获取它们的 string 表示形式,或反之。sstream 输入和输出操作可自动地把算术类型转化为相应的 string 表示形式,反过来也可以。
int val1 = 512, val2 = 1024; ostringstream format_message; // ok: converts values to a string representation format_message << "val1: " << val1 << "\n" << "val2: " << val2 << "\n";
// str member obtains the string associated with a stringstream istringstream input_istring(format_message.str()); string dump; // place to dump the labels from the formatted message // extracts the stored ascii values, converting back to arithmetic types input_istring >> dump >> val1 >> dump >> val2; cout << val1 << " " << val2 << endl; // prints 512 1024
![](https://img2024.cnblogs.com/blog/35695/202407/35695-20240713070336838-1837943664.jpg)