首页 > 代码库 > 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 库