//8.1 IO类
//到目前为止,我们已经使用过的IO类型和对象都是操纵char数据的。默认情况下,这些对象都是关联用户的控制台窗口的。
//当然,我们不能限制实际应用程序仅从控制台窗口进行IO操作,应用程序常常需要读写命名文件。而且,使用IO操作处理string
//中的字符会很方便。此外,应用程序还可能读写需要宽字符支持的语言。
//8.1.1 IO对象无拷贝或赋值
//8.1.2条件状态
//查询流的状态
//管理条件状态
//8.1.3管理输出缓冲
//每个输出流都管理一个缓冲区,用来保存程序读写的数据。例如,如果执行下面的代码
//os<<"please enter a value: ";
//文本串可能立即打印出来,但也有可能被操作系统保存在缓冲区中,随后再打印。有了缓冲机制,操作系统就可以将程序的
//多个输出操作组合成单一的系统级写操作。由于设备的写操作可能很耗时,允许系统将多个输出操作组合成单一的系统级写操作。
//导致缓冲刷新的原因有很多。
//1.程序正常结束,作为main函数的return操作的一部分,缓冲刷新被执行。
//2.缓冲区满时,需要刷新缓冲,而后新的数据才能继续写入缓冲区。
//3.我们可以使用操纵符如endl来显式刷新缓冲区。
//4.再每个输出操作之后,我们可以用操作符unitbuf设置流的内部状态,来清空缓冲区。默认情况下,对cerr是设置unitbuf的,因此写到cerr
// 的内容都是立即刷新的。
//5.一个输出流可能被关联到另一个流。在这种情况下,当读写被关联的流时,关联到的流的缓冲区会被刷新。例如,默认情况下,cin和cerr都关联到cout。
//因此,读cin或写cerr都会导致cout的缓冲区被刷新。
//刷新输出缓冲区
#include "iostream"
#include"fstream"
#include "vector"
#include"string"
#include "sstream"
using namespace std;
int main81() {
cout << "hi!" << endl;
cout << "hi!" << flush;
cout << "hi" << ends;
cout << unitbuf;
cout << "hi";
system("pause");
return 0;
}
//关联输入流和输出流
//当一个输入流被锻炼到一输出流时,任何试图从输入流读取数据的操作都会先刷新关联的输出流。
//标准库将cout和cin关联在一起。
//cin>>ival;
int main82() {
cin.tie(&cout);//仅仅是用来展示:标准库将cin和cout关联在一起
//old_tie指向关联到cin的流(如果有的话)
ostream *old_tie = cin.tie(nullptr);//cin不再与其他流关联
cin.tie(&cerr);//读取cin会刷新cerr而不是cout
cin.tie(old_tie);//重建cin和cout间的关联
return 0;
}
//8.2文件输入输出
//头文件fstream定义了三个类型来智齿文件IO:ifstream从一个给定文件中读取数据,ofstream从一个给定文件中写入数据,以及fstream可以读写给定文件。
//8.2.1使用文件流对象
//当我们想要读写一个文件时,可以定义一个文件流对象,并将对象与文件关联起来,每个文件流都定义了一个名为open的成员函数
//他完成一些系统相关的操作,来定位给定的文件,并视情况打开位读或写模式
//创建文件流对象时,我们可以提供文件名。如果提供了一个文件名,则open会被自动调用。
//ifstream in(ifile); //构造一个ifstream并打开给定文件
//ofstream out; //输出文件流并未关联到任何文件
int main83() {
//ifstream in("F:/FWNfiles/C++回炉/C++重造/io.txt");
ofstream out("F:/FWNfiles/C++回炉/C++重造/io.txt");
out << "周六保证不学习,周日学习不保证!";
out << endl;
out << "星期六保证不休息,星期天休息不保证!";
out << endl;
out << "运行之后就没有了?";
out << endl;
ifstream in("1.txt");
ofstream output("2.txt");
output << "love" << endl;
ifstream input("2.txt");
// system("pause");
return 0;
}
//8.2.2文件模式
//每个流都有一个关联的文件模式,用来指出如何使用文件。表8.4列出了文件模式和他们的含义
//以out模式打开文件会丢弃已有数据
//默认情况下,当我们打开一个ofstream时,文件的内容会被丢弃。阻止一个ofstream清空给定文件内容的方法是同时指定app模式
int main84() {
//在这几条语句中,file1都被截断
ofstream out("file1.txt");//隐含以输出模式打开文件并截断文件
ofstream out2("file1.txt", ofstream::out);//隐含截断文件
ofstream out3("file1.txt", ofstream::out | ofstream::trunc);
out << "1";
out3 << "3";
out2 << "2";
out << "4";
//为了保留文件内容,我们必须显式指定app模式
ofstream app("file2.txt", ofstream::app);//隐含为输出模式
app << "1";
ofstream app2("file2.txt", ofstream::out | ofstream::app);
app2 << "2";
ofstream ate("file2.txt", ofstream::out | ofstream::ate);
ate << "上山打老虎";
return 0;
}
//8.3string流
//sstream头文件定义了三个类型来智齿内存IO,这些类型可以向string写入数据,从string读取数据,就香string是一个IO流一样
//isstring从string读取数据,ostringstream向string写入数据,而头文件stringstream既可以从string读数据也可以向string写数据
//8.3.1使用istringstream
//假定又这样一个例子,假定有一个文件,列出了一些人和他们的电话号码。某些人只有一个号码,而另一些人则有多个——家庭电话
//工作电话,移动电话。我们的输入文件看起来可能是这样
//morgan 201552368 8625550123
//derw 9735550130
//iee 6095550132 20155550175 8005550000
//文件中每条记录都是以一个人名开始,后面跟随一个或多个电话号码。
//我们首先定义一个简单的类来描述输入数据:
struct PresonInfo
{
string name;
vector<string> phones;
};
int main85() {
string line, word;
vector<PresonInfo> peoole;
while (getline(cin,line))
{
PresonInfo info;
istringstream record(line);
record >>info.name;
while (record>>word)
{
info.phones.push_back(word);
peoole.push_back(info);
}
}
system("pause");
return 0;
}
//8.3.2使用ostringstream
//当我们逐步构造输出,希望最后一起打印时,ostringstream是很有用的。例如,对上一节的例子,我们可能逐个验证
//电话号码并逐个验证电话并改变其格式。如果所有号码都是有效的,我们希望输出一个新的文件,包含改变格式后的号码。
//对于那些无效的号码,我们不会将他们输出到新文件中,而是打印一条包含人名和无效号码的错误信息。
//由于我们不希望输出有无效电话号码的人,因此对每个人,直到验证完所有电话号码后才可以进行输出操作。但是,我们可以先将输出内容
//写入到一个内存ostringstream中。
int main() {
string line, word;
vector<PresonInfo> people;
while (getline(cin, line))
{
PresonInfo info;
istringstream record(line);
record >> info.name;
while (record >> word)
{
info.phones.push_back(word);
people.push_back(info);
}
}
for (const auto& entry:people)
{
ostringstream formatted, badNums;//每个循环步创建的对象
for (const auto& nums:entry.phones)
{
//if (!valid(nums))
{
badNums << " " << nums;
}
//else
// (formatted<<" "<<format(nums))
}
if (badNums.str().empty())
{
//os << entry.name << " " << formatted.str() << endl;
}
else
{
cerr << "input error: " << entry.name << " invalid number(s)" << badNums.str() << endl;
}
}
system("pause");
return 0;
}
//在此程序中,我们假定已有两个函数,valid和format,分别完成电话号码验证和改变格式的功能。
C++Primer 学习笔记 第八章 IO库
最新推荐文章于 2025-06-06 21:48:36 发布