C++ IO流

文章目录

  • C语言的输入与输出
  • 流是什么?
  • C++IO流
    • C++标准IO流
    • C++文件流
  • stringstream的简单介绍

C语言的输入与输出

在C语言中,我们使用最频繁的输入输出方式为: scanf 和 printf.

  1. scanf : 从输入设备(键盘)读取数据,并将值存放在变量中.
  2. printf: 将指定的文字/字符串输出到标准输出设备(屏幕).
    在这里插入图片描述

流是什么?

  • "流"即是流动的意思,是物质从一处向另一处流动的过程,是对一种有序连续且具有方向性的数据的抽象概述.
  • C++流是指信息从输入设备(如键盘)向内存输入和信息从内存向输出设备输出的过程,这种输入输出的过程被形象的比喻为"流".

流的特征为: 有序连续,具有方向性.

C++IO流

C++系统实现了一个庞大的类库,其中ios为基类,其他类都是直接或者间接继承自ios类.
在这里插入图片描述

C++标准IO流

C++标准库提供了4个全局流对象(cin、cout、cerr、clog).

  • 使用cout进行标准输出,即数据从内存流向控制台(显示器).
  • 使用cin进行标准输入,即数据通过键盘输入到程序中.
  • 使用cerr进行标准错误的输出.
  • 使用clog进行日志的输出.

注意:

  1. cin为缓冲流,键盘输入的数据保存在缓冲区中,当要提取时,是从缓冲区中提取,如果一次性输入过多,则多余的数据会保存在缓冲区中以供之后提取,如果输错了,必须在回车之前进行修改,如果回车键按下就无法修改了,只有将输入缓冲区的数据读取完之后的数据才要求输入新的数据.
int main()
{int a , b;cin >> a; //向放缓冲区中输入 1 , 2cout << a << endl;cin >> b; //直接从输入缓冲区提取2,不用认为输入cout << b << endl;return 0;
}

2.输入的数据类型必须与要提取的数据类型一致.

3.回车和空格都可以作为数据之间的分隔符,所以多个数据可以在一行输入,也可以分行输入.但是如果是字符型和字符串,则空格无法用cin输入,字符串中也不能有空格.回车键也无法读入.


int main()
{string s;cin >> s;          //输入:"hello yzh"cout << s << endl; //输出:"hello"return 0;
}

对于含有空格的字符串,我们可以尝试采用getline函数进行读取,因为getline函数只有遇到’\n’才会停止读取.

int main()
{string s;getline(cin, s); //输入: "hello yzh";cout << s << endl; //输出:"hello yzhreturn 0;
}

4:对于内置类型,cin和cout可以直接输入和输出相关数据,原因:标准库已经将所有内置类型的输入和输出全部重载了,

流插入: >>
在这里插入图片描述
流提取: <<
在这里插入图片描述
5:对于自定义类型,如果要支持cin和cout的标准输入输出,需要对<<和>>进行重载.

class Date
{friend ostream& operator << (ostream& out, const Date& d);friend istream& operator >> (istream& in, Date& d);
public:Date(int year = 1, int month = 1, int day = 1):_year(year), _month(month), _day(day){}
private:int _year;int _month;int _day;
};
istream& operator >> (istream& in, Date& d)
{in >> d._year >> d._month >> d._day;return in;
}
ostream& operator << (ostream& out, const Date& d)
{out << d._year << " " << d._month << " " << d._day;return out;
}
int main()
{Date de;cin >> de; //2023 7 6cout << de; //2023 7 6return 0;
}

6: 在线OJ中的输入和输出.

  • 对于IO类型的算法,一般需要循环输入.
  • 输出:严格按照题目的要求进行,不能多一个空格或者少一个空格.
  • 连续输入时,VS系列编译器在输入ctrl+Z时结束.

例如: C语言中的cin和C++中的scanf默认都是用空格和换行分割的.

输入格式:2023 07 06

int main()
{int year, month, day;cin >> year >> month >> day; // 2023 07 06scanf("%d%d%d", &year, &month, &day); // 2023 07 06return 0;
}

输入格式:20230706
要达到输入格式C语言可以利用sancf中规定年为4个位置,月为2个位置,日为2个位置.

int main()
{int year, month, day;scanf("%4d%2d%2d", &year, &month, &day); //输入格式:20230706return 0;
}

C++只能通过stoi函数将数字字符串按照年,月,日的格式进行分割,然后将数字字符串格式转换为整数.

int main()
{int year, month, day;string str;cin >> str;year = stoi(str.substr(0, 4));month = stoi(str. substr(4, 2));day = stoi(str.substr(6, 2));cout << year << "年" << month << "月" << day<<"日";
}

并且,C++中还可以通过while循环支持多行测试用例,当然,我们可以使用ctrl+z+换行给一个流读取结束的标志.

int main()
{int year, month, day;string str;while (cin >> str){year = stoi(str.substr(0, 4));month = stoi(str.substr(4, 2));day = stoi(str.substr(6, 2));cout << year << "年" << month << "月" << day<<"日";}return 0;
}

C++文件流

二进制读写; 在内存中如何存储,就如何写到磁盘文件上.

  • 优点: 读写快.
  • 缺点: 写入打文件,但是文件内容看不见.

文本读写: 序列化成字符串写出来,读回来也是字符串,

  • 可以看见具体内容.
  • 存在一个转换过程,读写速度慢.

C++根据文件内容的数据格式分为二进制文件和文本文件。采用文件流对象操作文件的一般步骤.

  1. 定义一个文件流对象
  • istream ifile(只输入用)
  • ofstream ofile(只输出用)
  • fstream iofile(既输入又输出用)

2.使用文件流对象的成员函数打开一个磁盘文件,使的文件流对象和磁盘文件之间建立联系.( 输入或者输出).

3.利用提取和插入运算符对文件进行读写操作,或者使用成员函数进行读写.

以下为C++IO流文本读,写以及二进制读写.

struct ServerInfo
{//char _address[32];  //用于二进制读写,必须采用字符数组,不能采用string类.string _address;  //用于文本读写,可以采用string类.int _port;};
class ConfigManager
{
public:ConfigManager(const char* filename = "sever.config"):_filename(filename){}//二进制写:将数据写道文件里面.void WriteBin(ServerInfo& info){ofstream ofs(_filename, ios_base::out | ios_base::binary); //以二进制覆盖写的方式打开文件.ofs.write((const char*)&info, sizeof(info));   //将目标大小的数据写入.}//二进制读,将文件里面的数据读取到内存中.void ReadBin(const ServerInfo& info){ifstream ifs(_filename, ios_base::in | ios_base::binary);//以二进制读的方式打开文件.ifs.read((char*)&info, sizeof(info));  //将目标大小的数据读取.}//文本读(输入到内存中)void ReadText1(ServerInfo& info){ifstream ifs(_filename, ios_base::in);ifs >> info._address >> info._port;}//文本写(输出到文件中)void WriteText1(ServerInfo& info){ofstream ofs(_filename, ios_base::out);ofs << info._address << endl;ofs << info._port << endl;}private:string _filename;  //配置文件.};

测试案例如下:

int main() {//写入数据(二进制)ServerInfo winfo = { "127.0.0.1",888 };ConfigManager cm;cm.WriteBin(winfo);//读取数据(二进制)/*ServerInfo rinfo;ConfigManager cm;cm.ReadBin(rinfo);cout << rinfo._address << endl;   //打印cout << rinfo._port << endl;*///文本写.//ServerInfo winfo = { "127.0.0.1",888};//ConfigManager cm;//cm.WriteText1(winfo);//文本读.//ServerInfo rinfo;//ConfigManager cm;//cm.ReadText1(rinfo);//cout << rinfo._address << endl;//cout << rinfo._port << endl;return 0;
}

注意:

  • 使用二进制读写时,如果目标数据由string类,vector类存储,那么写入到文件的时候并不是将数组的内容写入,而是将string字符串数组的地址,capacity等写入.该地址也对应着"写入文件"时这一进程.可是,当我们将从文件读取(输入)到内存中时,会将上一进程中写入的地址读取,可是,在新的进程中,该地址是无效的,对应着野指针.
  • 所以二进制读写不适合深浅拷贝的类,一般采用字符数组存储数据.

二进制读,写的自己实现

对文本读来说,我们可以调用ifstream类对象中的成员函数读取文本数据,这一过程也成为输入,步骤如下:

  • 创建ifs对象并二进制以读的形式当打开文件.
  • 创建输入缓冲区
  • 依次调用getline函数对文本数据行读取到缓冲区中.
  • 依次将缓冲区的数据放入对应的变量中.
	void ReadText( ServerInfo& info){ifstream ifs(_filename, ios_base::in | ios_base::binary);char buff[128];ifs.getline(buff, 128); //1info._address = buff; //将读取的数据放在对应的变量中.ifs.getline(buff, 128); //2info._port = stoi(buff);//将读取的数据转回整型变量中.}

对于文本写来说,我们也可ofstream类对象中的成员函数将数据写入文件中,这一过程也成为输出.步骤如下:

  • 创建ofs对象并二进制以写的形式当打开文件.
  • 依次将目标数据写入到文件中
	void WriteText(const ServerInfo& info){ofstream ofs(_filename, ios_base::out | ios_base::binary);ofs.write(info._address.c_str(), info._address.size());   //1ofs.put('\n'); //'n'分割数据,读取时方便分辨.const string str = to_string(info._port);//2ofs.write(str.c_str(), str.size());}

利用istream类对象中的get()函数读取Test.cpp文件中的数据(输入),然后再利用cout将打印出来.

int main()
{ifstream ifs("Test.cpp");char ch = ifs.get();while (ifs){cout << ch;ch = ifs.get();}return 0;
}

stringstream的简单介绍

在C++中,我们可以使用stringstream来将整型变量的数据达转换为字符串形式.主要有两种使用方式:
1.将数值数据格式转化为字符串.

int main()
{//方法一:int a = 10;string sa;stringstream s;s << a; //将int类型的a放入输入流s >> sa; //从s中抽取前面插入的int类型的值,赋值给string类型cout << sa << endl;//方法二:s.str(""); //将stringstream底层管理的string对象设置为""。s.clear(); //将上次转换状态清空掉//进行下一次转换double b = 3.14;s << b;sa = s.str(); //获取stringstream中管理的string类型(方式二)cout << sa << endl;return 0;
}

2.字符串拼接.

int main()
{//方法一:string rets;stringstream s;s << "hello" << "yzh"; //将多个字符串放入stringstream中s >> rets; cout << rets << endl;//方法二:s.str(""); //将stringstream底层管理的string对象设置为空字符串s.clear(); //将上次转换状态改变.s << "welcome" << " " << "to" << " " << "C++"; //将多个字符串放入stringstream中rets = s.str(); cout << rets << endl;return 0;
}

3.序列化和反序列化结构数据,将结构体多个内置类型数据转换为字符串类型.当然,如果自定义类型自定义写了流插入和流提取,那么便可以直接使用.

class Date
{friend ostream& operator << (ostream& out, const Date& d);friend istream& operator >> (istream& in, Date& d);
public:Date(int year = 1, int month = 1, int day = 1):_year(year), _month(month), _day(day){}
private:int _year;int _month;int _day;
};
istream& operator >> (istream& in, Date& d)
{in >> d._year >> d._month >> d._day;return in;
}
ostream& operator << (ostream& out, const Date& d)
{out << d._year << " " << d._month << " " << d._day;return out;
}
struct ChatInfo
{string _name;int _id;Date _date;string _msg;
};
int main()
{// 结构信息序列化为字符串ChatInfo winfo = { "张三", 135246, { 2022, 4, 10 }, "晚上一起看电影吧"};stringstream oss;oss << winfo._name << " " << winfo._id << " " << winfo._date << " "<< winfo._msg;string str = oss.str();cout << str << endl << endl;// 我们通过网络这个字符串发送给对象,实际开发中,信息相对更复杂,// 一般会选用Json、xml等方式进行更好的支持// 字符串解析成结构信息ChatInfo rInfo;stringstream iss(str);iss >> rInfo._name >> rInfo._id >> rInfo._date >> rInfo._msg;cout << "-------------------------------------------------------"<< endl;cout << "姓名:" << rInfo._name << "(" << rInfo._id << ") ";cout << rInfo._date << endl;cout << rInfo._name << ":>" << rInfo._msg << endl;cout << "-------------------------------------------------------"<< endl;return 0;
}

注意:

  • 序列化与反序列化也可以使用ostringstream和istringstream操作,效果与用法stringstream相同.
  • stringstream实际是在底层维护了一个string类型的对象用来保存结果。
  • stringstream在转换结尾时(即最后一个转换后),会将其内部状态设置为badbit,因此在下一次转换前必须调用clear将状态重置为goodbit才可以转换,但clear不会将stringstream底层的string对象清空。
  • 所以,我们可以使用s.str(“”)的方式将stringstream底层的string对象设置为空字符串,否则多次转换时,会将结果全部累积在底层string对象中。
  • 使用stringstream转换后可以使用 >> 运算符 也可以 使用使用s.str()将让stringstream返回其底层的string对象。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/22115.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

详解c++---c++11(下)

目录标题 default关键字delete关键字lambda表达式为什么会有lambda表达式lambda的用法多线程和lambdalambda的底层 可变参数模板emplace包装器为什么会有包装器包装器的使用 bind default关键字 C11可以让你更好的控制要使用的默认函数。假设你要使用某个默认的函数&#xff0…

Java中字符串相关的类

目录 String类 StringBuffer类 StringBuilder类 String类 String类&#xff1a;代表字符串。Java 程序中的所有字符串字面值&#xff08;如 "abc" &#xff09;都作为此类的实例实现。 String是一个final类&#xff0c;代表不可变的字符序列。 字符串是常量&…

webpack相关

在 webpack < 4 的版本中&#xff0c;通常将 vendor 作为一个单独的入口起点添加到 entry 选项中&#xff0c;以将其编译为一个单独的文件&#xff08;与 CommonsChunkPlugin 结合使用&#xff09;。而在 webpack 4 中不鼓励这样做。而是使用 optimization.splitChunks 选项…

Vim使用tips ---用鼠标定位代码

在vim界面里我们想用鼠标操作定位代码是不可以的&#xff01;&#xff01; 但是我们可以更改设置&#xff1a; 按下 Esc 键返回到普通模式shift&#xff1a; 输人命令 set mouse a回车 这时候我们就可以定位到代码啦&#xff01;&#xff01; 还可以批量选中复制和删除&…

【Docker】Docker高级网络(NetWork)

【Docker】Docker高级网络(NetWork) 文章目录 【Docker】Docker高级网络(NetWork)1. 概述2. 网络2.1 网桥类型2.2 创建网络自定义桥2.3 查看所有网络2.4 查看特定网络的细节2.5 删除特定网络2.6 多个容器使用指定网络 参考文档&#xff1a;高级网络配置 Docker – 从入门到实践…

[论文分享]MR-MAE:重构前的模拟:用特征模拟增强屏蔽自动编码器

论文题目&#xff1a;Mimic before Reconstruct: Enhancing Masked Autoencoders with Feature Mimicking 论文地址&#xff1a;https://arxiv.org/abs/2303.05475 代码地址&#xff1a;https://github.com/Alpha-VL/ConvMAE&#xff08;好像并未更新为MR-MAE模型&#xff09; …

nginx部署vue项目

nginx部署vue项目 一. vue配置讲解二. Nginx配置讲解三. vue项目部署到nginx 一. vue配置讲解 在vue.config.js文件中&#xff0c;module.exports是配置路由转发的&#xff0c;几个重要的属性讲解 ① publicPath publicPath: /ulane/, 此属性配置上&#xff0c;如果访问的路…

耳夹式骨传导耳机哪个牌子好?耳夹骨传导耳机盘点!

随着科技的日新月异&#xff0c;耳夹式骨传导耳机也在不断更新换代。市场上涌现出许多品牌&#xff0c;这使得消费者在购买时感到困惑。别担心&#xff01;我们为你整理了一些市场上口碑和销量优秀的品牌和耳夹式骨传导耳机产品&#xff0c;希望能帮到你。 一&#xff1a;南卡…

苹果iOS App Store上架操作流程详解:从开发者账号到应用发布

很多开发者在开发完iOS APP、进行内测后&#xff0c;下一步就面临上架App Store&#xff0c;不过也有很多同学对APP上架App Store的流程不太了解&#xff0c;下面我们来说一下iOS APP上架App Store的具体流程&#xff0c;如有未涉及到的部分&#xff0c;大家可以及时咨询&#…

​python接口自动化(二十八)--html测试 报告——下(详解) ​

简介 五一小长假已经结束了&#xff0c;想必大家都吃饱喝足玩好了&#xff0c;那就继续学习吧。一天不学习&#xff0c;自己知道&#xff1b;两天不学习&#xff0c;对手知道&#xff1b;三天不学习&#xff0c;大家知道&#xff1b;一周不学习&#xff0c;智商输给猪。好了开个…

【架构设计】高并发架构实战:从需求分析到系统设计

写在前面 很多软件工程师的职业规划是成为架构师&#xff0c;但是要成为架构师很多时候要求先有架构设计经验&#xff0c;而不做架构师又怎么会有架构设计经验呢&#xff1f;那么要如何获得架构设计经验呢&#xff1f; 1 高并发是什么 高并发是指系统在同一时间内处理的请求量…

js判断两个数组是增加还是删除

JS判断两个数组的数据&#xff0c;增加的数据以及删除的数据。 // 第一个参数是新数组&#xff0c;第二个参数是旧数 const compareArrays function(arr1, arr2 ) {let remove []let add []// 旧数据循环for (let i 0; i < arr2.length; i) {let item arr2[i];if (arr…