【C++进阶】C++中的IO流

目录

前言

1. C语言中的IO

2. 如何理解流

3. C++中的IO流

 3.1 C++中的标准IO

3.2 C++中的文件IO

 4. stringstream

总结


前言

        C语言中的I/O接口十分强大,但使用起来有些繁琐。好在C++中的I/O方式为我们解决了这些问题,让数据的读写操作变得更加简洁和便捷; 在本文中,我们将探讨C++中的I/O流;

在这里插入图片描述

1. C语言中的IO

         C语言中最常用的输入输出的方式就是 scanf 和printf ; scanf(): 从标准输入设备(键盘)读取数据,并将值存放在变量中。printf(): 将指定的文字/字符串输出到标准输出设备(屏幕)。注意宽度输出和精度输出控制;
        C语言借助了相应的缓冲区(内部封装)来进行输入与输出;

 如何理解:

  1. 屏蔽掉低级I/O的实现, 低级IO需要依赖底层操作系统的实现, 屏蔽掉底层细节便于程序的可移植性;
  2.  可以实现行读取的操作, 在计算机内部是没有行这个概念的, 有了缓冲区就可以根据行进行数据解析, 更为方便

2. 如何理解流

        “流”即是流动的意思,是物质从一处向另一处流动的过程,是对一种有序连续具有方向性的数据( 其单位可以是bit,byte,packet )的抽象描述

         C++流是指信息从外部输入设备(键盘)向计算机内部(内存)输入和从内存向外部输出设备(显示器)输出的过程。这种输入输出的过程被形象的比喻为“流”。

        为了实现这种流动,C++定义了I/O标准类库,这些每个类都称为流/流类,用以完成某方面的功能;

3. C++中的IO流

         C++系统实现了一个庞大的类库,其中ios为基类,其他类都是直接或间接派生自ios类

         从图中结构可以看出它使用了菱形继承;  istream 主要是进行输入, ostream主要是进行输出, 然而如果使用输入输出需要包含不同的类那就有点不便了, 所以它有采用了一个iostream的类去继承 istream 和 ostream ; 在这样在使用时只需用iostream就可以既可以输入又可以输出;

 3.1 C++中的标准IO

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

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

 在使用时候必须要包含文件并引入std标准命名空间

 注意:

  •  cin为缓冲流。键盘输入的数据保存在缓冲区中,当要提取时,是从缓冲区中拿。如果一次输入过多,会留在那儿慢慢用,如果输入错了,必须在回车之前修改,如果回车键按下就无法挽回了。只有把输入缓冲区中的数据取完后,才要求输入新的数据。
  • 输入的数据类型必须与要提取的数据类型一致,否则出错。出错只是在流的状态字state中对应位置位(置1),程序继续。
  • 空格和回车都可以作为数据之间的分格符,所以多个数据可以在一行输入,也可以分行输入。但如果是字符型和字符串,空格和回车也依然无法无法读入;
  • cin和cout可以直接输入和输出内置类型数据,原因:标准库已经将所有内置类型的输入和输出全部重载了;
  •  OJ中的输入和输出:

 常见的几种:

// 单个元素循环输入
while(cin>>a)
{// ...
}// 多个元素循环输入
while(c>>a>>b>>c)
{// ...
}// 整行接收
while(cin>>str)
{// ...
}

        使用while(cin>>i)去流中提取对象数据时,调用的是operator>>,返回值是应该是 istream 类型的对象,这里为什么可以做逻辑条件值?

        因为 istream的对象又调用了operator bool,operator bool调用时如果接收流失败,或者有结束标志,则返回false;

  • 对于自定义类型,如果要支持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){}operator bool(){// 这里是随意写的,假设输入_year为0,则结束if (_year == 0)return false;elsereturn true;}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 d(2022, 4, 10);cout << d;
}

3.2 C++中的文件IO

 文件的格式主要有两种: 文本文件二进制文件;

 在使用时也非常简单, 文件流对象有三种:

  • ifstream ifile(只输入用)
  • ofstream ofile(只输出用)
  • fstream iofile(既输入又输出用)

 文本形式读写文件:

// 写
ofstream ofs(_filename); // 默认以文本形式打开一个文件不需要添加任何选项(默认为覆盖写)
ofs << value1 << " " << value2 << " " << value3;// 读
ifstream ifs(_filename);
ofs >> value1 >> value2 >> value3; // 当有多个值时,流提取时默认将换行和空格视为分割符

 二进制形式进行读和写:

// 写
ofstream ofs(_filename, ios_base::out | ios_base::binary);// 覆盖写 + 二进制; 
ofs.write((const char*)&info, sizeof(info)); // info为结构化字段, 取结构体的地址,取的字节个数// 读
ifstream ifs(_filename, ios_base::in | ios_base::binary);
ifs.read((char*)&info, sizeof(info)); // //读到这个结构体中

 在使用时可以根据自己的需求封装一下, 这样进行文件读写时也会更加方便简洁;

 写入方式:

  • 追加写 选项: ios_base::app
  • 覆盖写 选项: ios_base::out (默认)

 另外特别需要注意:

 二进制读写一个特别坑的地方,  文本读写并不会存在问题;

使用string类型存储数据, 然后把string类型的数据以二进制形式写入到文件中时;

我的测试环境是VS2022, 感兴趣的小伙伴可以去测试一下:

struct ServerInfo
{/*char _address[132];*/string _address;double _x;Date _date;
};class BinIO
{
public:BinIO(const char* filename = "info.bin"):_filename(filename){}//写void Write(const ServerInfo& winfo){ofstream ofs(_filename, ofstream::out | ofstream::binary);ofs.write((char*)&winfo, sizeof(winfo));}// 读void Read(ServerInfo& rinfo){ifstream ifs(_filename, ofstream::in | ofstream::binary);ifs.read((char*)&rinfo, sizeof(rinfo));//读到这个结构体中}private:string _filename;
};int main()
{ServerInfo winfo = { "https://legacy.cplusplus.com", 12.13, { 2024, 1, 1 } };BinIO bin;bin.Write(winfo);ServerInfo info;bin.Read(info);cout << info._address << endl;cout << info._x << endl;cout << info._date << endl;return 0;
}

当ServerInfo 使用 string 类型时, 读数据出来的时候程序就会异常崩溃;

主要分为两种情况:

读写在一个进程中时,读是可以读取到,但最后程序还是会崩,这是由于浅拷贝的问题

  • string内部存在一个指针、大小、容量
  • 写进去时会将指针地址、大小容量什么都写入到了文件当中
  • 当读取时,将所有数据读给一个对象
  • 这就导致两个对象的指针指向同一块空间,进而导致程序崩溃

读和写不在一个进程中:

  • 不同的进程读取数据的对象中的string内部变成了野指针
  •  因为读进来的string中它的指针指向的空间已经被销毁
  • 这里导致string内容读取不到
  • 所有使用二进制读写时要特别注意容器
     

 最好的避免方法就是不使用容器;

 4. stringstream

 这里作为拓展, 只需要知道 stringstream怎么使用即可;

在C语言中,如果想要将一个整形变量的数据转化为字符串格式,如何去做?

  1. 使用itoa()函数
  2. 使用sprintf()函数
     

这两个接口以及非常的好用了, 尤其是sprintf, 在一些限制只能使用C的情况下, 格外好用;

但是使用时就比较繁琐;

        两个函数在转化时,都得需要先给出保存结果的空间,那空间要给多大呢,就不太好界定,
而且转化格式不匹配时,可能还会得到错误的结果甚至程序崩溃;

 在C++中,可以使用stringstream类对象来避开此问题。
        在程序中如果想要使用stringstream,必须要包含头文件。在该头文件下,标准库三个类:
istringstream、ostringstream 和 stringstream,分别用来进行流的输入、输出和输入输出操
作,本文主要介绍stringstream;

当需要拼接多个字符串时C++中string的方式就有点显得僵硬;

	string sql2;sql2 += "select * from t_scroe where name = '";sql2 += name;sql2 += "'";cout << sql2 << endl;

 而stringstream就很好的解决了这些问题;

stringstream的功能非常强大:

  • 将数值类型数据格式化为字符串
#include<sstream>
int main()
{int a = 12345678;string sa;stringstream s;s << a;s >> sa;cout << sa << endl; // 12345678s.str(""); // 将底层管理的string对象置为""s.clear(); // 清空s, 不清空会转化失败double d = 12.34;s << d;s >> sa;string sValue;sValue = s.str(); // str()方法:返回stringsteam中管理的string类型cout << sValue << endl; // 12.34return 0;
}
  • 字符串拼接
int main()
{stringstream sstream;// 将多个字符串放入 sstream 中sstream << "first" << " " << "string,";sstream << " second string";cout << sstream.str() << endl; //  first string, second string// 清空 sstreamsstream.str("");sstream << "third string";cout << sstream.str() << endl; // third stringreturn 0;
}
  • 序列化和反序列化结构数据
struct ChatInfo
{string _name; // 名字int _id;      // idDate _date;   // 时间string _msg;  // 聊天信息
};int main()
{ChatInfo winfo = { "张三", 135246, { 2024, 2, 24 }, "xxxxxx" };stringstream oss;//stringstream继承了ostringstream和istringstreamoss << winfo._name << endl;oss << winfo._id << endl;oss << winfo._date << endl;oss << winfo._msg << endl;cout << oss.str() << endl;// 网络输出ChatInfo rinfo;string str = oss.str();stringstream iss(str);iss >> rinfo._name;iss >> rinfo._id;// 注意这里流提取默认空格和换行作为分割符,date自己实现的ostream分隔符应该使用空格或换行// 否则会提取出错iss >> rinfo._date;iss >> rinfo._msg;cout << "-------------------------------------------------------" << endl;cout << "姓名:" << rinfo._name << "(" << rinfo._id << ") ";cout << rinfo._date << endl;cout << rinfo._name << ":>" << rinfo._msg << endl;cout << "-------------------------------------------------------" << endl;return 0;
}

 在学习时, 进行序列化和反序列化操作时一般使用的是Json;

 使用注意:

  • stringstream实际是在其底层维护了一个string类型的对象用来保存结果。
  • 多次数据类型转化时,一定要用clear()来清空,才能正确转化,但clear()不会将stringstream底层的string对象清空。
  • 可以使用s. str("")方法将底层string对象设置为""空字符串。
  • 可以使用s.str()将让stringstream返回其底层的string对象。
  • stringstream使用string类对象代替字符数组,可以避免缓冲区溢出的危险,而且其会对参数类型进行推演,不需要格式化控制,也不会出现格式化失败的风险,因此使用更方便,更安全

总结

        C++中的IO方式解决了C语言IO接口使用繁琐的问题, 让数据的读写操作变得更加简洁; 同时C++的IO接口在使用时也有许多的注意点 ,  学习C++中的IO , 在后续无论是工作, 还是学习都非常的重要;  好了以上便是本文的全部内容, 希望对你有所帮助, 感谢阅读!

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

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

相关文章

动手学深度学习(Pytorch版)代码实践 -循环神经网络-57长短期记忆网络(LSTM)

57长短期记忆网络&#xff08;LSTM&#xff09; 1.LSTM原理 LSTM是专为解决标准RNN的长时依赖问题而设计的。标准RNN在训练过程中&#xff0c;随着时间步的增加&#xff0c;梯度可能会消失或爆炸&#xff0c;导致模型难以学习和记忆长时间间隔的信息。LSTM通过引入一组称为门…

【卡尔曼滤波器】DR_CAN 2 学习笔记:_数据融合_协方差矩阵_状态空间方程_观测器问题

【卡尔曼滤波器】2_数学基础_数据融合_协方差矩阵_状态空间方程_观测器问题 非常重要1 数据融合 data fusion 有俩秤,各自有自己的正态分布:俩秤是相互独立的:俩秤都不准,但标准差都符合正态分布 正态分布又叫做高斯分布 向左、向右 都是2, 标准差是2覆盖了68.4 %的可能:…

开启HIVE中分区表支持中文字段

进入hive表&#xff1a; use hive; #修改hive database编码 alter database hive default character set utf8; #修改table编码 alter table PARTITIONS default character set utf8; alter table PARTITION_KEY_VALS default character set utf8; alter table SDS default cha…

机器学习和AI智能写作对未来文案编辑的影响

欢迎关注小知&#xff1a;知孤云出岫 目录 机器学习和AI智能写作对未来文案编辑的影响1. 简介2. AI智能写作工具的现状3. AI智能写作的优势3.1 提高效率3.2 降低成本3.3 数据驱动的个性化 4. AI智能写作的挑战4.1 创造力和独创性4.2 道德和伦理问题4.3 技术限制 5. 行业变化5.…

【排序 - 插入排序 和 希尔排序】

插入排序&#xff08;Insertion Sort&#xff09;是一种简单直观的排序算法&#xff0c;它的工作原理是逐步构建有序序列。在排序过程中&#xff0c;它将未排序的元素逐个插入到已排序的部分中&#xff0c;从而在每次插入时扩展已排序序列的长度。 原理介绍 插入排序的基本思…

RAG实践:ES混合搜索BM25+kNN(cosine)

1 缘起 最近在研究与应用混合搜索&#xff0c; 存储介质为ES&#xff0c;ES作为大佬牌数据库&#xff0c; 非常友好地支持关键词检索和向量检索&#xff0c; 当然&#xff0c;支持混合检索&#xff08;关键词检索向量检索&#xff09;&#xff0c; 是提升LLM响应质量RAG(Retri…

Java 8革新:现代编程的全新标准与挑战

文章目录 一、方法引用二、接口默认方法三、接口静态方法四、集合遍历forEach()方法 一、方法引用 方法引用是Java 8中一种简化Lambda表达式的方式&#xff0c;通过直接引用现有方法来代替Lambda表达式。 方法引用使得代码更加简洁和易读&#xff0c;特别是在处理函数式接口时&…

大数据专业创新人才培养体系的探索与实践

一、引言 随着大数据技术的迅猛发展&#xff0c;其在各行各业中的应用日益广泛&#xff0c;对大数据专业人才的需求也日益增长。我国高度重视大数据产业的发展&#xff0c;将大数据作为国家战略资源&#xff0c;推动大数据与各行业的深度融合。教育部也积极响应国家战略&#…

JVM:字节码文件

文章目录 一、Java虚拟机的组成二、字节码文件的组成1、基本信息2、常量池3、字段4、方法5、属性 三、常用的字节码工具1、javap -v 命令2、jclasslib插件3、阿里arthas 一、Java虚拟机的组成 二、字节码文件的组成 1、基本信息 魔数、字节码文件对应的Java版本号访问标识&am…

Docker 使用基础(2)—镜像

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;秒針を噛む—ずっと真夜中でいいのに。 0:34━━━━━━️&#x1f49f;──────── 4:20 &#x1f504; ◀️ ⏸ …

Vue组件通信props和$emit用法

父传子&#xff0c;通过props 子传父&#xff0c;通过$emit App.vue <template><div class"app" style"border: 3px solid #000; margin: 10px">我是APP组件<!-- 1.给组件标签&#xff0c;添加属性方式 赋值 --><!-- 添加属性传值 …

【java算法专场】双指针(下)

611. 有效三角形的个数 目录 611. 有效三角形的个数 算法思路 算法代码 LCR 179. 查找总价格为目标值的两个商品 算法思路 算法代码 HashSet 双指针 15. 三数之和 算法思路 算法代码 18. 四数之和 ​编辑算法思路 算法代码 611. 有效三角形的个数 算法思路 算法…

前端面试题(CSS篇六)

一、浏览器如何判断是否支持 webp 格式图片 &#xff08;1&#xff09;宽高判断法。通过创建image对象&#xff0c;将其src属性设置为webp格式的图片&#xff0c;然后在onload事件中获取图片的宽高&#xff0c;如果能够获取&#xff0c;则说明浏览器支持webp格式图片。如果不能…

IAR 编译优化等级详解

目录 1.编译时优化器何时介入 2.编译优化等级汇总 3.优化项解读 3.1 代码移动 3.2 函数内联 3.3 循环交换 3.4 循环展开 3.5 公用表达式消除 3.6 链接阶段的优化 4 小结 大家好&#xff0c;这里是快乐的肌肉。 最近在迁移工程到IAR编译器上&#xff0c;发现编译优化…

AI赛道成功的“小”AI平台,都在做什么?

在深入了解30多家跨界拓展AI赛道业务的企业后&#xff0c;我们发现大家对目前的AI市场存在一定程度的误解&#xff1a;即认为在AI领域想要分一杯羹&#xff0c;只需要搞几个API&#xff0c;把大语言模型、绘画、视频、数字人等功能都放上去&#xff0c;可能就有机会占一席之地了…

递归 迷宫问题-java

1&#xff09;findWay方法是为了找出走出迷宫的路径&#xff0c;找到返回true&#xff0c;否则返回false 2&#xff09;&#xff08;i&#xff0c;j&#xff09;是老鼠的位置&#xff0c;初始化的位置为&#xff08;1&#xff0c;1&#xff09; 3&#xff09;因为是递归找路&am…

2024年网络监控软件排名|10大网络监控软件是哪些

网络安全&#xff0c;小到关系到企业的生死存亡&#xff0c;大到关系到国家的生死存亡。 因此网络安全刻不容缓&#xff0c;在这里推荐网络监控软件。 2024年这10款软件火爆监控市场。 1.安企神软件&#xff1a; 7天免费试用https://work.weixin.qq.com/ca/cawcde06a33907e6…

【Linux】一文看懂Linux静态库和动态库

文章目录 一、静态库&#xff08;Static Library&#xff09;二、动态库&#xff08;Dynamic Library&#xff09;三、静态库和动态库的比较四、静态库的制作与使用五、动态库的制作与使用六、如何区分链接的是动态库还是静态库 在Linux系统编程中&#xff0c;库是一组预先编写…

【全面讲解下Foxit Reader】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

3年经验的B端产品经理,应该是什么水平?

问你一个问题&#xff1a;你觉得3年经验的B端产品经理&#xff0c;应该是什么水平&#xff1f;很多朋友可能也没有仔细想过&#xff0c;自己3年后应该达到一个什么水平&#xff1f;能做什么体量的业务&#xff1f;要能拿多少薪资&#xff1f; 前几天和一个B端产品经理聊天&…