第14讲对标准库做了一些简单的介绍,从这一讲开始依次对各个标准库进行详解。这一讲是IO库
IO库
为了支持不同种类的IO处理操作,C++定义了多种IO类型。
iostream定义了用于读写流的基本类型。
- istream 从流读取数据
- ostream 向流写入数据
fstream定义了读写命名文件的类型。
- ifstream 从文件读取数据
- ofstream 向文件写入数据
sstream定义了读写内存string对象的类型。
- istringstream 从string读取数据
- ostringstream 向string写入数据
类型fstream和sstream都继承自iostream,我们如何使用iostream就如何使用前两个。也就是我们如何使用cin和cout就如何使用前两个。
需要注意一点:IO对象不能拷贝不能赋值,所以将IO对象作为参数或返回值类型时,需要用引用,同时,不能用const。
流的状态大概就这一点有用:
当我们输入文件结束符时,cin会进入错误状态。s.clear()将流s中所有条件状态位复位,将流的状态设置为有效。
管理输出缓冲
每个输出流都管理一个缓冲区,用来保存程序读写的数据。如果执行os<<“lalalalalla” 文本串可能会打印出来,但也有可能保存到了操作系统的缓冲区中,随后再打印。
导致缓冲刷新(数据被打印出来)几个常见原因:
- 程序正常结束,作为return操作的一部分
- endl
- 缓冲区满
除了endl可以刷新缓冲区,还有两个。
cout<<"hi"<<endl; //输出hi和换行符,然后刷新缓冲区
cout<<"hi"<<flush;//输出hi,然后刷新缓冲区,不附加任何额外字符
cout<<"hi"<<ends;//输出hi和一个空字符,然后刷新缓冲区
如果想在每次输出操作后都刷新缓冲区,我们可以使用unitbuf操作符。
它告诉流接下来每次写操作后都进行一次flush操作。而nounitbuf则重置流,恢复原先的缓冲机制。
cout<<unitbuf;
cout<<nounitbuf;
文件输入输出
ifstream从一个给定文件读取数据,ofstream向一个给定文件写入数据。使用它们跟使用cin和cout一样。
fstream定义了一些新的操作,我们可以对fstream,ifstream,ofstream调用这些操作。
fstream fstrm;
fstream fstrm(s);//创建fstream,打开名为s的文件,s可以是字符串
fstream fstrm(s,mode);//以mode方式打开
fstrm.open(s);//打开s文件
fstrm.close();
fstrm.is_open();//返回bool,文件是否成功打开且尚未关闭
因为上面说了,fstream和sstream都继承自iostream。因此在需要istream&的地方,可以使用ifstream对象(这不就是派生与继承那块儿的虚函数嘛)。
比如之前的Sales_data类,我们不传入cin而是传入ifstream。
int main()
{
ifstream in("Sales_data_text_in.txt");
ofstream out("Sales_data_text_out.txt");
Sales_data total;
if (read(in, total))
{
Sales_data trans;
while (read(in, trans))
{
if (total.isbn() == trans.isbn())
{
total.combine(trans);
}
else
{
print(out, total);
total = trans;
}
}
print(out, total);
}
else
{
out << "No data\n";
}
}
程序可以正常运行,并写入到Sales_data_text_out.txt文件中。
上面我们用到的是以构造函数的方式打开,我们也可以使用open函数打开。
ofstream out;
out.open("cuinan.text");
if(out)
{}
这样打开最好进行一个检验。如果打开失败,out条件会为 假。
当我们想用out绑定另一个文件时,必须先关闭此文件
out.close();
out.open("lalala.text");
if(out)
{}
还有一句话:当一个fstream对象被销毁时,close会自动被调用。
一个小练习:
将文件的内容读入到一个vector中。
int main()
{
ifstream ifstr("test_fstream.txt");
vector<string> vec;
string str;
if (ifstr)
{
while (getline(ifstr,str))
{
vec.push_back(str);
}
cout << "读取完成" << endl;
for (auto s : vec)
{
cout << s << endl;
}
}
else
{
cout << "加载失败" << endl;
}
}
注意看这两个程序有什么区别
int main()
{
ifstream ifstr("test_fstream.txt");
vector<string> vec;
string str;
if (ifstr)
{
while (ifstr>>str)
{
vec.push_back(str);
}
cout << "读取完成" << endl;
for (auto s : vec)
{
cout << s << endl;
}
}
else
{
cout << "加载失败" << endl;
}
}
文件还是那个文件
文件模式
app模式:每次写操作前均定位到文件末尾
默认情况下,当我们打开一个ofstream,文件的内容会被丢弃,阻止一个ofstream清空给定文件内容的方法是同时指定app模式。
ofstream app("file2",ofstream::app);
ofstream out("test_fstream.txt",ofstream::app);
if (out)
{
out << "lalala";
}
else
{
cout << "加载失败" << endl;
}
//当然,也可以这样 out.open("test_fstream.txt",ofstream::app)
以追加方式打开。
.
string读写流
sstream头文件定义了三个类型来支持内存IO
istringstream:从string读数据
ostringstream:向string写数据
stringstream:既可读数据又可写数据
stringstream有几个特异性操作
sstream strm;
sstream strm(s); //保存s的一个拷贝
strm.str(); //返回strm所保存的string的拷贝
strm.str(s); //将s拷贝到strm中
.
istringstream的使用
.
当我们的某些工作是对整行文本进行处理,其他一些工作是处理行内的一些单词时,经常会使用到istringstream。
比如下面这个例子
将这些存入到一个vector中。
下面是程序
struct PersonInfo
{
string name;
vector<string> phone;
};
int main()
{
ifstream ifstr("test_sstream.txt");
vector<PersonInfo> people;
if (ifstr)
{
string str;
while (getline(ifstr, str))
{
PersonInfo temp;
string phoneNum;
istringstream istr(str);
istr >> temp.name;
while (istr >> phoneNum)//当字符串读完后,会触发文件结束符
{
temp.phone.push_back(phoneNum);
}
people.push_back(temp);
}
}
else
{
cout << "加载失败" << endl;
}
for (auto s : people)
{
cout << s.name << " ";
for (auto s1 : s.phone)
{
cout << s1 << " ";
}
cout << endl;
}
}
可以看出,对于一个字符串,如果我们希望挨个处理里面的每个单词,那istringstream是最好的选择。
再来一个小练习:
将文件中的一行一行字符串保存到vector中,然后用istringstream读取每一行中的各个单词。
int main()
{
vector<string> vec;
ifstream ifstr("test_sstream_2.txt");
if (ifstr)
{
string str;
while (getline(ifstr, str))
{
vec.push_back(str);
}
for (auto s : vec)
{
istringstream isstr(s);
string temp;
while (isstr >> temp)
{
cout << temp << " ";
}
}
}
else
{
cout << "加载失败" << endl;
}
return 0;
}
ostringstream的使用
当我们希望逐步构造输出,最后一起打印时,使用ostringstream是很有用的。
使用的时候就将各个字符串<<给ostringstream就可以了。
string str;
ostringstream result;
result << str;
result.str()//打印的时候可以这样
好,这就是IO库。下一张是顺序容器。