1. 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 的。
  2. badbit 标志着系统级的故障,如无法恢复的读写错误。如果出现了这类错误,则该流通常就不能再继续使用了。如果出现的是可恢复的错误,如在希望获得数值型数据时输入了字符,此时则设置 failbit 标志,这种导致设置 failbit 的问题通常是可以修正的。eofbit 是在遇到文件结束符时设置的,此时同时还设置了 failbit。

  3. 常量 含义 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
  4. 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的流状态情况相同,但当执行完第二条语句,本质区别就显露出来。

  5. 下面几种情况将导致缓冲区的内容被刷新,即写入到真实的输出设备或者文件:
    • 程序正常结束。作为 main 返回工作的一部分,将清空所有输出缓冲区。
    • 在一些不确定的时候,缓冲区可能已经满了,在这种情况下,缓冲区将会在写下一个值之前刷新。
    • 用操纵符(第 1.2.2 节)显式地刷新缓冲区,例如行结束符 endl。
    • 在每次输出操作执行完后,用 unitbuf 操作符设置流的内部状态,从而清空缓冲区。
    • 可将输出流与输入流关联(tie)起来。在这种情况下,在读输入流时将刷新其关联的输出缓冲区。
  6. 我们的程序已经使用过 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
  7. 如果需要刷新所有输出,最好使用 unitbuf 操纵符。这个操纵符在每次执行完写操作后都刷新流:
    cout << unitbuf << "first" << " second" << nounitbuf;
    等价于:
    cout << "first" << flush << " second" << flush;
    nounitbuf 操纵符将流恢复为使用正常的、由系统管理的缓冲区刷新方式。
  8. fstream 对象一旦打开,就保持与指定的文件相关联。如果要把 fstream 对象与另一个不同的文件关联,则必须先关闭(close)现在的文件,然后打开(open)另一个文件:要点是在尝试打开新文件之前,必须先关闭当前的文件流。open 函数会检查流是否已经打开。如果已经打开,则设置内部状态,以指出发生了错误。接下来使用文件流的任何尝试都会失败。
  9. 关闭流(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();
    }

  10. 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 模式打开的文件会被清空:丢弃该文件存储的所有数据。
  11. 模式是文件的属性而不是流的属性,每次打开文件时都会设置模式
    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");

  12. out 打开文件做写操作,删除文件中已有的数据
    out | app 打开文件做写操作,在文件尾写入
    out | trunc 与 out 模式相同
    in 打开文件做读操作
    in | out 打开文件做读、写操作,并定位于文件开头处
    in | out | trunc 打开文件做读、写操作,删除文件中已有的数据

  13. 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
posted on 2011-05-03 20:38  cppfans  阅读(232)  评论(0编辑  收藏  举报