首页 > 代码库 > C++primer第八章 标准 IO 库

C++primer第八章 标准 IO 库

  前面的程序已经使用了多种 IO 标准库提供的工具:
  • istream(输入流)类型,提供输入操作。
  • ostream(输出流)类型,提供输出操作。
  • cin(发音为 see-in):读入标准输入的 istream 对象。
  • cout(发音为 see-out):写到标准输出的 ostream 对象。
  • cerr(发音为 see-err):输出标准错误的 ostream 对象。cerr 常用于程序错误信息。
  • >> 操作符,用于从 istream 对象中读入输入。
  • << 操作符,用于把输出写到 ostream 对象中。

8.1. 面向对象的标准库

技术分享

  IO 对象不可复制或赋值

ofstream out1, out2;out1 = out2; // error: cannot assign stream objects// print function: parameter is copiedofstream print(ofstream);out2 = print(out2); // error: cannot copy stream objects

  一、在第九章看到的,只有支持复制的元素类型可以存储在 vector 或其他容器类型里。

  二、形参或返回类型也不能为流类型。如果需要传递或返回 IO对象,则必须传递或返回指向该对象的指针或引用

ofstream &print(ofstream&); // ok: takes a reference, no copywhile (print(out2)) { /* ... */ } // ok: pass reference to out2

8.2. 条件状态

  实现 IO 的继承正是错误发生的根源。一些错误是可恢复的;一些错误则发生在系统底层,位于程序可修正的范围之外

  技术分享

技术分享

int ival;cin >> ival;
if (cin)// ok to use cin, it is in a valid statewhile (cin >> word)// ok: read operation successful ...

  条件状态

  某些程序则需要更详细地访问或控制流的状态,此时,除了知道流处于错误状态外,还必须了解它遇到了哪种类型的错误。

  badbit 标志着系统级的故障,如无法恢复的读写错误。如果出现了这类错误,则该流通常就不能再继续使用了

  如果出现的是可恢复的错误,如在希望获得数值型数据时输入了字符,此时则设置 failbit 标志,这种导致设置 failbit的问题通常是可以修正的。

  eofbit 是在遇到文件结束符时设置的,此时同时还设置了 failbit

  如果 bad、fail 或者 eof中的任意一个为 true,则检查流本身将显示该流处于错误状态。类似地,如果这三个条件没有一个为 true,则 good 操作将返回 true。

  clear 和 setstate 操作用于改变条件成员的状态。

clear 操作将条件重设为有效状态。在流的使用出现了问题并做出补救后,如果我们希望把流重设为有效状态,则可以调用 clear 操作使用 setstate 操作可打开某个指定的条件,用于表示某个问题的发生。

流状态的查询和控制

int ival;// read cin and test only for EOF; loop is executed even if there areother IO failureswhile (cin >> ival, !cin.eof()) {    if (cin.bad()) // input stream is corrupted; bail out    throw runtime_error("IO stream corrupted");    if (cin.fail()) { // bad input        cerr<< "bad data, try again"; // warn the user        cin.clear(istream::failbit); // reset the stream        continue; // get next input    }// ok to process ival}

  条件状态的访问

  rdstate 成员函数返回一个 iostate 类型值,该值对应于流当前的整个条件状态

// remember current state of cinistream::iostate old_state = cin.rdstate();cin.clear();process_input(); // use cincin.setstate(old_state); // now reset cin to old state

多种状态的处理

常常会出现需要设置或清除多个状态二进制位的情况。

// sets both the badbit and the failbitis.setstate(ifstream::badbit | ifstream::failbit);

 8.3. 输出缓冲区的管理

系统将字符串字面值存储在与流 os 关联的缓冲区中。下面几种情况将导致缓冲区的内容被刷新,即写入到真实的输出设备或者文件:

1. 程序正常结束。作为 main 返回工作的一部分,将清空所有输出缓冲区。
2. 在一些不确定的时候,缓冲区可能已经满了,在这种情况下,缓冲区将会在写下一个值之前刷新。
3. 用操纵符(第 1.2.2 节)显式地刷新缓冲区,例如行结束符 endl。
4. 在每次输出操作执行完后,用 unitbuf 操作符设置流的内部状态,从而清空缓冲区。
5. 可将输出流与输入流关联(tie)起来。在这种情况下,在读输入流时将刷新其关联的输出缓冲区。

  输出缓冲区的刷新

  使用过 endl 操纵符,用于输出一个换行符并刷新缓冲区。除此之外,C++ 语言还提供了另外两个类似的操纵符。第一个经常使用的 flush,用于刷新流,但不在输出中添加任何字符。第二个则是比较少用的 ends,这个操纵符在缓冲区中插入空字符 null,然后后刷新它

cout << "hi!" << flush; // flushes the buffer; adds no datacout << "hi!" << ends; // inserts a null, then flushes the buffercout << "hi!" << endl; // inserts a newline, then flushes the buffer

unitbuf 操纵符

 这个操纵符在每次执行完写操作后都刷新流:

cout << unitbuf << "first" << " second" << nounitbuf;

等价于:
cout << "first" << flush << " second" << flush;

8.4. 文件的输入和输出

fstream 头文件定义了三种支持文件 IO 的类型:
1. ifstream,由 istream 派生而来,提供读文件的功能。
2. ofstream,由 ostream 派生而来,提供写文件的功能。
3. fstream,由 iostream 派生而来,提供读写同一个文件的功能。

8.4.1. 文件流对象的使用

// construct an ifstream and bind it to the file named ifileifstream infile(ifile.c_str());// ofstream output file object to write file named ofileofstream outfile(ofile.c_str());

为 ifstream 或者 ofstream 对象提供文件名作为初始化式,就相当于打开了特定的文件。

ifstream infile; // unbound input file streamofstream outfile; // unbound output file stream

在使用 fstream 对象之前,还必须使这些对象捆绑要读写的文件:

infile.open("in"); // open file named "in" in the current directoryoutfile.open("out"); // open file named "out" in the current directory

检查文件打开是否成功

// check that the open succeededif (!infile) {    cerr << "error: unable to open input file: "    << ifile << endl;    return -1;}

这个条件与之前测试 cin 是否到达文件尾或遇到某些其他错误的条件类似。检查流等效于检查对象是否“适合”输入或输出。

将文件流与新文件重新捆绑

fstream 对象一旦打开,就保持与指定的文件相关联。如果要把 fstream 对象与另一个不同的文件关联,则必须先关闭(close)现在的文件,然后打开(open)另一个文件:要点是在尝试打开新文件之前,必须先关闭当前的文件流。

如果已经打开,则设置内部状态,以指出发生了错误。接下来使用文件流的任何尝试都会失败。

ifstream infile("in"); // opens file named "in" for readinginfile.close(); // closes "in"infile.open("next"); // opens file named "next" for reading

清除文件流的状态

// for each file in the vector(每次打开时创建新的文件流)while (it != files.end()) {    ifstream input(it->c_str()); // open the file;    // if the file is ok, read and "process" the input        if (!input)            break; // error: bail out!        while(input >> s) // do the work on this file            process(s);        ++it; // increment iterator to getnext file}    
ifstream input;vector<string>::const_iterator it = files.begin();// for each file in the vectorwhile (it != files.end()) {    input.open(it->c_str()); // open the file    // if the file is ok, read and "process" the input    if (!input)        break; // error: bail out!    while(input >> s) // do the work on this file        process(s);    input.close(); // close file when we‘re done with it    input.clear(); // reset state to ok    ++it; // increment iterator to get next file}

8.4.2. 文件模式

  在打开文件时,无论是调用 open 还是以文件名作为流初始化的一部分,都需指定文件模式(file mode)

  技术分享技术分享

  默认时,与 ifstream 流对象关联的文件将以 in 模式打开,该模式允许文件做读的操作:与 ofstream 关联的文件则以 out 模式打开,使文件可写。以out 模式打开的文件会被清空:丢弃该文件存储的所有数据。

  对于用 ofstream 打开的文件,要保存文件中存在的数据,唯一方法是显式地指定 app 模式打开:

// output mode by default; truncates file named "file1"ofstream outfile("file1");// equivalent effect: "file1" is explicitly truncatedofstream outfile2("file1", ofstream::out | ofstream::trunc);// append mode; adds new data at end of existing file named "file2"ofstream appfile("file2", ofstream::app);

对同一个文件作输入和输出运算

  默认情况下,fstream 对象以 in 和 out 模式同时打开。当文件同时以 in和 out 打开时不清空。如果打开 fstream 所关联的文件时,只使用 out 模式,而不指定 in 模式,则文件会清空已存在的数据。如果打开文件时指定了 trunc模式,则无论是否同时指定了 in 模式,文件同样会被清空。

模式是文件的属性而不是流的属性

  每次打开文件时都会设置模式

ofstream outfile;// output mode set to out, "scratchpad" truncatedoutfile.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" truncatedoutfile.open("out");

打开模式的有效组合

 技术分享

8.5. 字符串流

标准库定义了三种类型的字符串流:

• istringstream,由 istream 派生而来,提供读 string 的功能。
• ostringstream,由 ostream 派生而来,提供写 string 的功能。
• stringstream,由 iostream 派生而来,提供读写 string 的功能。

要使用上述类,必须包含 sstream 头文件。

技术分享

stringstream 对象的和使用

string line, word; // will hold a line and word from input,respectivelywhile (getline(cin, line)) { // read a line from theinput into line    // do per-line processing    istringstream stream(line); // bind to stream to the line we read    while (stream >> word){ // read a word from line    // do per-word processing    }}

stringstream 提供的转换和/或格式化

int val1 = 512, val2 = 1024;ostringstream format_message;// ok: converts values to a string representationformat_message << "val1: " << val1 << "\n"<< "val2: " << val2 << "\n";

  用 istringstream 读 string 对象,即可重新将数值型数据找回来。

// str member obtains the string associated with a stringstreamistringstream 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 typesinput_istring >> dump >> val1 >> dump >> val2;cout << val1 << " " << val2 << endl; // prints 512 1024

 

 

 

 

 

C++primer第八章 标准 IO 库