IO流
C++中的IO类主要有3种:
- iostream头文件 主要控制读写流
-
istream 读流类型
-
ostream 写流类型
-
iostream 读写流类型
- fstream头文件 主要用于文件读写
- ifstream 读文件类型
- ofstream 写文件类型
- fstream 读写文件类型
- sstream头文件 主要用于读写内存中的string对象
- istringstream 读string类型
- ostringstream 写string类型
- stringstream 读写string类型
其继承关系如下:
注意IO对象是无法被拷贝的,所以IO操作的函数通常以引用方式传递IO对象,由于读写IO对象会导致变化所以不能是底层const。
文件IO流
文件IO是由fstream头文件控制的。首先来看一下fstream含有的方法,其中包含了ifstream, ofstream与fstream三种类型
其步骤一般都是:
- 打开文件(直接通过构造函数或open方法)
- 读写文件
- 关闭文件(通过close方法)
来看一个实例:
void FileRead(const string &strFileName) {
// ifstream in(strFileName); 也可以通过构造来打开文件
ifstream in;
in.open(strFileName); // 通过open打开文件
if (!in.is_open()) { // is_open方法判断打开是否成功
cout << "打开失败" << endl;
return;
}
string strLine;
while (!in.eof()) { // 用eof()方法来判断ios_base::eofbit标志位是否置位,代表是否读到文件末尾
getline(in, strLine); // 从ifstream流中逐行读取
cout << strLine << endl; // 输出到标准输出中
}
in.close(); // 关闭ifstream流
}
实际上在并不需要调用in.close()来关闭文件,因为在FileRead结束后,其ifstream对象被销毁导致析构函数被调用,其中会自动帮我们调用in.close()来关闭文件。
对文件对象进行操作时还可以指定特定的文件模式,来看一下有哪些模式:
ifstream默认是以ios::in方式打开的,ofstream则是ios::out方式打开,并其默认会清空文件内所有内容相当于带上了ios::trunc标志进来。如果不想写入文件时文件被截断清空就带上app标志,表示是往文件末尾增加内容, 来看一下:
ofstream out("filename", ios::out | ios::app);
这样就可以做到打开文件后不清空文件内容了, ios::ate和ios::binary可以用于任何类型的文件流对象也可以与in, out, app...等模式合用
string流
string流由sstream头文件控制,其包含了sstringstream, istringstream, ostringstream类型。可以把string对象绑定到这三种类型上进行内存上的string对象操作。
绑定方法可以通过构造函数, 即sstream strm(s)或者调用str(string)方法来进行,下面给一个实例:
struct PersonInfo {
string name;
vector<string> phones;
};
void istringstreamTest(vector<PersonInfo> &people) {
string line, word;
istringstream record;
while (getline(cin, line)) {
PersonInfo info;
record.clear();
record.str(line); // 通过str()方法来绑定string对象
record >> info.name;
while (record >> word)
info.phones.push_back(word);
people.push_back(info);
}
for (auto& k : people) {
cout << k.name << " ";
for (auto& k : k.phones)
cout << k;
cout << endl;
}
}
这段代码中由于istringstream对象为局部中的全局变量,所以每次使用str()进行绑定的时候要清空里面已经绑定的内容。
下面给出如何通过构造方法绑定string对象的代码:
void istringstreamExec() {
string str;
getline(cin, str);
istringstream ins(str); // 通过构造方法来绑定string对象
while (ins >> str) {
cout << str << "\n";
}
}
接下去使用一个比较符合的例子来看一下如何使用ostringstream对象,来看代码:
struct PersonInfo {
string name;
vector<string> phones;
};
void istringstreamTest(vector<PersonInfo> &people) {
string line, word;
istringstream record;
while (getline(cin, line)) {
PersonInfo info;
record.clear();
record.str(line);
record >> info.name;
while (record >> word)
info.phones.push_back(word);
people.push_back(info);
}
}
bool valid(const string &str) {
for (auto& k : str)
if (k < '0' || k > '9')
return(false);
return(true);
}
// 如果输入的号码中有非数字成员则提示错误否则按照正常方式输出
void ostringstreamTest(ostream &os) {
vector<PersonInfo> v;
istringstreamTest(v);
for (const auto& entry : v) {
ostringstream formatted, badNums;
for (const auto& nums : entry.phones) {
if (!valid(nums))
badNums << " " << nums;
else
formatted << " " << nums;
}
if (badNums.str().empty())
os << entry.name << " " << formatted.str() << endl;
else
cerr << "input error: " << entry.name << " invalid numbers " << badNums.str() << endl;
}
}
上面的代码把之前istringstream的例子也用上了。首先从标准输入中获取姓名与电话并存入一个vector<string>容器中保存。接下去通过ostringstream对象来分别保存全是数字的电话和非纯数字的电话并分别输出出来。
最后来看一下sstream头文件中的类型能够执行的操作吧
IO流的标志位
IO对象的读写可能有失败,成功,错误等等....的状态,C++为了让我们判断状态特定提供了如下的条件状态函数和标志:
s.eof()方法会判断strm::eofbit是否被置位,是返回true否则false
s.fail() 方法会判断strm::failbit是否被置位, 是返回true否则false
s.good(), s.bad()控制着badbit与goodbit, 具体同上
s.clear()会清除所有IO对象状态, 变成初始状态
来看一个实例, 该实例类似于一个栈操作:
void process_read(istream &s) {
int iNum;
cout << "输入一个数字:";
s >> iNum;
}
void bitTest() {
ios_base::iostate old_state = cin.rdstate(); // 获取现在的标志情况
cin.clear(); // 清空现有标志
process_read(cin);
cin.setstate(old_state); // 回复之前的标志情况
}
看一下如何对IO标志进行复位
void ResetTest() {
ios_base::iostate st = cin.rdstate();
cin.setstate(st & ~cin.failbit & ~cin.badbit & ~cin.eofbit | cin.goodbit);
}
上面是让一切存在问题的标志位复位而成功标志位置位的代码段
(完)