-
C++不直接处理输入输出,而是通过一族定义在标准库中的类型来处理IO,这些类型支持从设备读取数据、向设备写入数据的IO操作,设备可以是文件、控制台窗口等;
-
之前已经使用的IO库设施:istream类型、ostream类型、cin、cout、cerr、>>运算符、<<运算符、getline函数;
头文件 类型 iostream istream/wistream 从流读数据 ostream/wostream 向流写数据 iostream/wiostream 读写流 fstream ifstream/wifstream 从文件读数据 ofstream/wofstream 向文件写数据 fstream/wfstream 读写文件 sstream istringstream/wistringstream 从string读数据 ostringstream/wostringstream 向string写数据 stringstream/wstringstream 读写string 宽字符版本的数据和函数以一个w开始,如wcin对应cin的宽字符版对象。
IO类
-
IO对象不能拷贝或赋值,也不能将形参或返回类型设置为流类型:
ofstream out1, out2; out1 = out2; // 错误,流对象不能赋值 ofstream print(out1); // 错误,函数不能以ofstream为形参,不能以ostream为返回类型 out2 = print(out1); // 错误,不能拷贝流对象
-
条件状态
IO库条件状态 strm::badbit 流已崩溃 strm::failbit 一个IO操作失败 strm::eofbit 流到达了文件结束 strm::goodbit 指出流未处于错误状态,此值保证为0 s.eof() 若流s的eofbit置位,则返回true s.fail() 若流s的failbit或者badbit置位,则返回true s.bad() 若流s的badbit置位,则返回true s.good() 若流s的goodbit置位,则返回true s.clear() 将流s中所有条件状态复位,将流的状态设置为有效,返回void -
代码通常应该在使用一个流之前检查它是否处于良好状态:
while (cin >> word);
-
-
管理输出缓冲
-
有了缓冲机制,操作系统就可以将程序的多个输出操作组合成单一的系统级写操作;
-
刷新输出缓冲区:
cout << "hi!" << endl; // 输出内容和一个换行,然后刷新缓冲区 cout << "hi!" << flush; // 输出内容,然后刷新缓冲区 cout << "hi!" << ends << 1; // 输出内容和一个空字符,然后刷新缓冲区。
- 如果程序异常终止,输出缓冲区不会被刷新;
-
-
关联输入和输出流
-
当一个输入流被关联到一个输出流时,任何试图从输入流读取数据的操作都会先刷新关联的输出流。标椎库将cout和cin关联在一起:
cin >> ival; // cout被刷新
-
交互式系统应该关联输入输出流,这样能保证所有输出,都会在读操作之前被打印出来,否则可能出现输入后的回应是输入前的输出的情况;
-
istream和ostream类型的tie成员都只能接收ostream *类型参数:
cin.tie(&cout); cin.tie(&cin); // 错误,无此函数 cout.tie(&cerr); cout.tie(&cin); // 错误,无此函数
-
解除关联:
cin.tie(nullptr);
-
文件输入输出
-
头文件fstream定义了三个类型来支持文件IO:ifstream;ofstream;fstream;
-
fstream头文件中继承自iostream的行为:
-
用IO运算符(<<和>>)来读写文件;
-
用getline从一个ifstream读取数据:
-
getline(cin,line);
-
-
fstream中增加新的成员来管理与流关联的文件:
fstream特有操作 含义 fstream fstrm 创立一个未绑定的文件流 fstream fstrm(s) 创立一个fstream,并打开名为s的文件 fstream fstrm(s) 与前一个函数类似,但按指定mode打开文件 fstrm.open(s) 打开名为s的文件,并将文件与fstrm绑定 fstrm.close() 关闭与fstrm绑定的文件 fstrm.close() 返回一个bool值,指出与fstrm关联的文件是否成功打开且尚未关闭 -
使用文件流对象
-
用fstream代替iostream&;
-
成员函数open和close:如果定义了一个空文件流对象,可以随后调用open来将它与文件关联起来,首先必须关闭已经关联的文件:
ifstream in(ifile); ofstream out; out.open(ifile+".copy")
因为调用open可能失败,失败后failbit会被置位,所以最好检测open是否成功:
if (out)
-
-
自动构造和析构:当一个fstream对象被销毁时,close会自动被调用。
-
文件模式:
- in:以读方式打开,只可以对ifstream或fsteam对象设置in模式(默认与ifstream关联的文件以in模式打开);
- out:以写方式打开只可以对ofstream或fsteam对象设置out模式(默认与ofstream关联的文件以out模式打开);
- 以out模式打开文件会丢失已有数据;
- 保留被ofstream打开的文件中已有数据的唯一方法是显示制定app或in模式。
string流
-
string头文件定义了三个类型来支持内存IO:
-
istringstream从string读取数据;
-
ostringstream向string写入数据;
-
stringstream既可读数据也可写数据。
stringstream特有操作 含义 sstream strm 创立一个未绑定的stringstream对象 sstream strm(s) 创立一个sstream对象,保存string s的一个拷贝 strm.str() 返回strm所保存的string的拷贝 strm.str(s) 将string s 拷贝到strm中,返回void
-
-
使用istringsteam
-
当我们的某些工作是对整行文本进行处理,而其他工作是处理行内的单个单词时,通常可以使用istringstream:
struct PersonInfo { string name; vector<string> phones; }; string line, word; vector<PersonInfo> people; while (getline(cin, line)) {//从标准输入读取整条记录 PersonInfo info; istringstream record(line); // 将记录绑定到刚读入的行,record不变 record >> info.name; //从一个string读取一个单词作为名字 while (record >> word) {//从一个string读取电话号码 info.phones.push_back(word); } people.push_back(info); }
-
-
使用ostringstream
-
当我们逐步构造输出,希望最后一起打印时,可以使用ostringstream对象:
for (const auto &entry : people) { // 遍历每一条信息 ostringstream formatted, badNums; for (const auto &nums : entry.phones) { // 遍历每一条信息中的电话号码 if (!valid(nums)) { // 如电话号不合法 badNums << " " << nums; // 以字符串形式存入badNums } else { formatted << " " << format(nums); // 如合法,将字符串以format函数返回的格式存入formatted } } if (badNums.str().empty()) { // 如没有不合法的电话号 cout << entry.name << " " << formatted.str() << endl; } else { cerr << "input error: " << entry.name << "invalid number(s) " << badNums.str() << endl; } }
-