yo!这里是c++IO流相关介绍

目录

前言

C语言的输入输出

C++IO流基本介绍

流的概念

IO流类库

iostream

fstream

stringstream

后记


前言

        学过C语言的输入输出相关知识点的童鞋应该多多少少会觉得有些许麻烦,反正我就是这么觉得的,scanf、printf等函数不仅数量众多,而且转化格式必须匹配,否则会得到错误的结果,有些函数还必须得预留出保存结果得空间,而这个空间又不好界定。那这就是C语言这套面向过程的输入输出相关函数使用的弊端,在c++面向对象的环境中,这些输入输出功能必定会被封装成类,正如大家熟知的cin、cout就是相关类多定义出来的对象,使用起来非常之舒服,那么c++的输入输出就叫做IO流。下面会先回忆一下C语言的输入输出函数,对比之下来拓展学习c++IO流,接下来就开始吧!

C语言的输入输出

        初学C语言时,想必大家一定经常用scanf、printf两个函数输入输出吧,但是对于fprintf、fscanf、sprintf、sscanf等函数,大部分同学应该是见过都很少用过,这些函数是后面学习到字符串和文件两部分知识点才会接触到的函数,也是用于输入输出的。下面我们分别大概介绍一下:

  • scanf:

  • printf:

        其中,第一个参数是一个常量字符指针,第二个参数是可变参数列表,表示用户自定义传入参数个数,返回值int表示按照指定的格式符正确读入/输出的数据的个数,但如果输入/输出数据与指定格式不符,则会产生错误,函数会立即终止,设置错误码,并返回已经成功读取/输入的数据的个数。

  • fscanf:

  • fprintf:

        可见,fprintf、fscanf函数与printf、scanf函数不同的只是多了一个参数——文件指针。回想一下,其实scanf函数默认是从键盘拿数据,因此fscanf函数是从指定文件拿数据,而printf默认是输出到显示屏,fprintf则是输出到指定文件。

  • sscanf:

  • sprintf:

  • snprintf:

        对于sscanf、sprintf函数也是一样,不同的地方在于多了一个参数——常量字符指针,因此sscanf是从一个字符串拿数据,而sprintf是将数据按照指定格式输出到一个字符串当中。snprintf更多了一个参数——字符个数,可以指定输入到字符串中的字符个数。

C++IO流基本介绍

  • 流的概念

        是对一种有序连续且具有方向性的数据( 其单位可以是bit、byte、packet )的抽象描述,而C++流是指信息从外部输入设备(如键盘)向计算机内部(如内存)输入和从内存向外部输出设备(显示器)输出的过程,这种过程被形象的比喻为“流”,具有有序连续、方向性的特性。

  • IO流类库

        为了实现这种流动,C++定义了I/O标准类库,如下图,这些每个类都称为流/流类,用以完成某方面的功能。其中ios为基类,其他类都是直接或间接派生自ios类。其中,不看第三列,派生类分为三种——iostream、fstream、stringstream,而第三列的cin、cout等是iostream定义出的对象,其中cin、cout也是我们自学习c++以来经常使用的输入输出流。宏观来看,iostream是对scanf、printf的替换,fstream是对fscanf、fprintf的替换,stringstream是对sscanf、sprintf的替换,下面分别介绍:

iostream

        iostream类库是istream、ostream类库合并而来,没什么别的意义,就是定义了这一个头文件,两个类的功能都可以使用。istream是输入流类,定义出cin进行标准输入即数据通过键盘输入到程序中,ostream是输出流类,定义出cout、cerr、clog,其中cout进行标准输出,即数据从内存流向显示屏,cerr用来进行标准错误的输出,以及clog进行日志的输出,这三个对象现在基本没有区别,只是应用场景不同。下面强调几个使用过程中的重点注意事项。

        1.空格和回车都可以作为数据之间的分格符,因此多个数据可以在一行输入,也可以分行输 入。但同时数据如果是字符型和字符串,则空格将无法用cin输入,也不能将空格通过键盘输入到字符串中。 

eg(输入多个值的方法):

如果遇到数据之间没有加空格或换行的情况呢?可能c++方法要比C语言方法稍复杂一点。

        2.在笔试一些oj题时,有很多题目需要循环输入得到多个数据,c++的方法就很简单,对于一个值循环输入:

while(cin>>a)
{//...
}

对于多个值循环输入:

while(cin>>a>>b>>c)
{//...
}

        大部分oj题的输入数据都是用空格或换行分割,因此使用以上方法拿到数据绝对没有任何问题。此外还值得提一嘴的是在vs系列编译器下连续输入时输入ctrl+z停止输入。

3. istream类型转换为逻辑判断值

        为什么上面的cin>>a在输入结束之后会停止循环,那肯定是while条件为假,但是cin>>a之后的返回值依旧是istream类型(istream& operator>> (int& val);),这该如何知道这是真是假呢?其实在istream类型当中,有这样一个成员函数——explicit operator bool() const{},不看explicit和const两个关键字,可以看到这个函数是没有返回值的,其实并不是,这是它的特殊实现方式,返回值就是bool类型,因为我们需要一个逻辑判断值,所以在operator后加上bool,然后函数体内就可以实现将istream类型转bool值得逻辑,实则就是看指向键盘数据的标识符是否指向结尾,指向结尾说明拿到了所有的数据,之后返回false,while循环条件拿到false则循环输入结束。这样说有点混乱,因为拿不到istream类型的实现机制,下面举两个例子:

1)如下图,类A我们实现了构造函数,那么我们相当于实现了将一个内置类型转换为一个自定义类型的功能,其实就是一种隐式类型转换;此时我们也想实现将一个自定义类型转换为一个内置类型的功能,比如说转换为int类型,那么我们就可以operator加上int实现这样一个函数,函数体内写上转为内置类型的逻辑,也就是拿到成员变量,将其返回出来,实现成功。

eg1:

 2)以下代码块实现一个Date类型和能够将其输入输出的operator重载函数。其中我们想要实现一个将这个Date类型转换为bool类型的功能,就是成员函数operator加上bool,函数体内实现转换逻辑,这里比如说是看year变量,为0返回false,为非0返回true,如此就实现了将自定义类型转内置类型的功能。

eg2:

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;
}

fstream

        不同于iostream的是,c++并没有提供像cin、cout这样的全局对象供我们使用,这里就需要我们自己去定义,包含头文件<fstream>后,三种定义方式如下:

  • 只输入用:ifstream 对象名(文件名)
  • 只输出用:ofstream 对象名(文件名)
  • 输入输出两个都能用:fstream 对象名(文件名)

        定义好之后,对象的用法就如同cin、cout一样了。举个例子,定义一个类ServerInfo作为文件IO的数据,包括ip地址、端口号、时间(前面模拟实现Date类),再定义一个类Consoler对一个文件实现文本读、文本写、二进制读、二进制写的功能,构造函数就是传入一个文件名即可。

        因为文件分为文本文件和二进制文件,所以有四个读写函数。对于二进制写,ofstream定义一个对象ofs,其中第一个参数就是文件名,第二个参数表示是二进制读写,之后使用write函数将信息数据写入文件;二进制读也是一样,使用read函数将信息数据读出来;对于文本写,不需要加第二个参数,因为默认就是文本读写,之后使用如同cin、cout的形式读写数据。注意要分清:ifs对应cin,cin是将键盘数据读到内存中,而ifs是将文件数据读到内存中;ofs对应cout,cout是将内存数据写到显示屏,而ifs是将内存数据写到文件中。

        综上,二进制文件和文本文件的读写方式不一样,c++文件流的优势就是可以对内置类型和自定义类型,都使用一样的方式,去流插入和流提取文件数据,不过前提是要自定义类型需要重载>> 和 <<。

eg:

class ServerInfo
{
public:char _ipaddr[32];int _port;Date _date;
};class Consoler
{
public:Consoler(const char* filename):_filename(filename){}//二进制写void WriteBin(const ServerInfo& info){ofstream ofs(_filename, ios_base::out | ios_base::binary);/*ofs << info._ipaddr << endl;ofs << info._port << endl;ofs << info._date << endl;*/   //这样写的话还是文本写ofs.write((char*)&info, sizeof(info));}//二进制读void ReadBin(ServerInfo& info){ifstream ifs(_filename, ios_base::out | ios_base::binary);ifs.read((char*)&info, sizeof(info));cout << info._ipaddr << endl;cout << info._port << endl;cout << info._date << endl;}//文本写void WriteText(const ServerInfo& info){ofstream ofs(_filename);ofs << info._ipaddr << endl;ofs << info._port << endl;ofs << info._date << endl;}//文本读void ReadText(ServerInfo& info){ifstream ifs(_filename);ifs >> info._ipaddr >> info._port >> info._date;cout << info._ipaddr << endl;cout << info._port << endl;cout << info._date << endl;}
private:string _filename;
};int main()
{ServerInfo info = { "192.168.1.1",28,{2024,1,26} };Consoler clr("draft.txt");clr.ReadBin(info); //二进制读clr.WriteBin(info); //二进制写clr.ReadText(info); //文本读clr.WriteText(info); //文本写return 0;
}

stringstream

        stringstream库的学习可以参考fstream,只不过第一个参数不是文件指针,而是string类型的对象,包含<sstream>后,就可以将数据输入到一个string中,也可以将string中的数据读出来。stringstream库分为istringstream库和ostringstream库,使用stringstream定义的对象可以读也可以写,使用istringstream定义的对象只可以写,使用ostringstream定义的对象只可以读,下面举几个例子简单说明一下用法。

1.不同数值类型与string之间的转换

eg:

#include <iostream>
#include <sstream>
#include <string>using namespace std;int main()
{//stringstream oss;   //一开始字符串流中啥也没有//stringstream oss("8888");   //一开始字符串流中就存在一个8888的字符串,默认是覆盖写stringstream oss("8888 ", ios_base::out | ios_base::ate);   //追加写int i = 123;double d = 3.14;string s = "hello";oss << i <<" " << d <<" " << s;cout << oss.str() << endl;return 0;
}

2.序列化和反序列化

        在通过网络传递信息的过程中,我们是需要一个string表示各种信息,比如说qq中发送的一条信息,包括发送者、发送对象、发送时间、发送内容等等,将这些信息序列化成一个字符串发送过来,接收后将这个字符串反序列化出来得到这些信息,这个过程就可以用到stringstream类。 

eg:

class QQInfo
{
public:string _name;Date _date;string _msg;
};int main()
{QQInfo info = { "张三",{2024,2,2},"你吃饭了没?" };//序列化stringstream oss;oss << info._name << " " << info._date << " " << info._msg;string str = oss.str();//通过网络发送这个str//...//反序列化QQInfo info2;stringstream iss(str);iss >> info2._name >> info2._date >> info2._msg;//验证cout << info2._name << " | " << info2._date << " | " << info2._msg << endl;return 0;
}

注意:

        1.stringstream实际上是在其底层维护了一个string类型的对象

        2.可以使用s. str("")方法将底层string对象设置为空字符

        3.可以使用s.str()将让stringstream返回其底层的string对象

        总的来说,stringstream使用string类对象代替字符数组,可以避免缓冲区溢出的危险,而且其会对参数类型进行推演,不需要格式化控制,也不会出现格式化失败的风险,因此使用更方便,更安全

后记

        从上面的学习可以看出,c++IO流是一个庞大的类库,很多类都是直接或间接派生基类所得,非常符合c++的世界观,使用起来非常方便,基类能支持的,子类都可以使用。此外,无论是输入输出方式、格式、类型安全、缓冲区和错误处理,C++的IO流相较于C语言的输入输出更加高级、安全和方便使用。而且从学习成本上看,当我们学会使用iostream类的使用,fstream、string stream类的使用也是得心应手。因此建议多多使用c++IO流来输入输出,拜拜!


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

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

相关文章

20240202在WIN10下使用whisper.cpp

20240202在WIN10下使用whisper.cpp 2024/2/2 14:15 【结论&#xff1a;在Windows10下&#xff0c;确认large模式识别7分钟中文视频&#xff0c;需要83.7284 seconds&#xff0c;需要大概1.5分钟&#xff01;效率太差&#xff01;】 83.7284/4200.1993533333333333333333333333…

测试工作(新入职)感悟

背景&#xff1a;我之前在小规模传统公司&#xff0c;工作强度一般&#xff0c;早九晚六&#xff0c;偶尔加班。现在就职的是大型同行业互联网公司&#xff0c;工作强度大&#xff0c;早九晚九&#xff0c;目前已经入职两个礼拜。 基于这个背景&#xff0c;新工作对我是比较有…

使用 Go 发送微信群消息

关注公众号【爱发白日梦的后端】分享技术干货、读书笔记、开源项目、实战经验、高效开发工具等&#xff0c;您的关注将是我的更新动力&#xff01; 背景 最近的某个副业需要我写一个脚本&#xff08;脚本内容就不说了&#xff09;&#xff0c;需要通知群成员&#xff0c;尽快地…

云原生业务全流程DevOps配置预研与实践

背景 我在一个二线城市&#xff08;山东济南&#xff09;&#xff0c;相对与北上广深杭这些IT业发达的城市来说&#xff0c;济南IT业对于业内新技术的接受度是有点慢的&#xff0c;国内很多一线大厂早先几年前就开始实践使用的技术&#xff0c;我们这边也是近两年才开始慢慢兴…

如何计算模型的复杂度(参数量,FLOPs)

参考 如何计算神经网络模型的复杂度 深度学习卷积、全连接层、深度可分离层参数量和FLOPs计算公式 概念 Params&#xff1a;模型的参数量。&#xff08;空间复杂度&#xff09;FLOPs&#xff1a;FLoating point Operations&#xff0c;前向推理的计算量。&#xff08;时间复…

open与json细节篇

open open函数 流程&#xff1a; 1.打开文件 2.操作文件 3.关闭文件 模式&#xff1a; #二进制 rb读取二进制&#xff0c;比如图片 wb写入二进制 返回bytes,字节 r只读,文件不存在会报错 w只写&#xff0c;文件不存在会创建&#xff0c;存在则覆盖原始内容 x只写&#xff0c;文…

C++函数分文件编写之VScode版

VScode实现函数的分文件编写 1.下载插件创建项目2.分文件编写内容3.修改主函数文件名 我在分享内容时经常用的软件是VScode&#xff0c;相信有些内存敏感或需要VScode便利性的小伙伴也是更愿意使用VScode。那么接下来我们就盘一盘怎样使用VScode实现分文件编写。 1.下载插件创建…

函数大聚会(c++题解)

题目描述 输入一个整数n。 1、判断它是否为素数&#xff0c;是输出“Y,不是输出“N”. 2、输出这个数的各位数字之和。 3、求出这个数所有约数的和。 4、求出1到n的和。 5、输出这个数的倒序数&#xff08;不包含前导0&#xff09;。 输入格式 一行一个整数。 输出格式 五…

2024 Flutter 重大更新,Dart 宏(Macros)编程开始支持,JSON 序列化有救

说起宏编程可能大家并不陌生&#xff0c;但是这对于 Flutter 和 Dart 开发者来说它一直是一个「遗憾」&#xff0c;这个「遗憾」体现在编辑过程的代码修改支持上&#xff0c;其中最典型的莫过于 Dart 的 JSON 序列化。 举个例子&#xff0c;目前 Dart 语言的 JSON 序列化高度依…

使用Java实现最少活跃数负载均衡算法

引言 在分布式系统中&#xff0c;负载均衡是一项关键技术&#xff0c;它能够确保各个服务器之间的负载相对均衡&#xff0c;提高系统性能和可靠性。本文将介绍一个简单而实用的最少活跃数负载均衡算法的Java实现。该算法通过选择当前活跃数最小的服务提供者&#xff0c;以确保…

来看看Tomcat和Web应用的目录结构

在前面两篇大致了解了Tomcat的架构和运行流程&#xff0c;以及Tomcat应用中的web.xml。 聊一聊Tomcat的架构和运行流程&#xff0c;尽量通俗易懂一点-CSDN博客 来吧&#xff0c;好好理解一下Tomcat下的web.xml-CSDN博客 那接下来&#xff0c;再看看Tomcat的目录&#xff0c;…

vue-3d-model

vue-3d-model - npm GitHub - hujiulong/vue-3d-model: &#x1f4f7; vue.js 3D model viewer component 通过该插件降低Threejs的使用难度 vue项目加载三维模型&#xff0c;我把模型放在了服务器的tomcat里面&#xff0c;需要对tomcat的fbx项目文件夹设置跨域&#xff0c;如…

踩坑STM32CubeMX生成Makefile工程无法使用printf(“%f“)

过去一年偶有接触STM32开发时都是使用STM32CubeMX生成Makefile的工程&#xff0c;具体开发环境见配置Clion用于STM32开发&#xff08;Makefile&#xff09;&#xff0c;但没想到今天在使用printf打印输出浮点数时无法正常输出&#xff0c;不仅printf无法使用&#xff0c;其他涉…

详解Skywalking 采集springboot 应用日志的方法(内附源码)

大家都知道Skywalking 的链路追踪功能非常强大&#xff0c;可以帮助用户深入了解应用程序中各个组件之间的依赖关系。在实际应用中&#xff0c;往往需要将链路追踪数据与日志数据结合起来进行综合分析。Skywalking 提供了 Trace Log 结合插件&#xff0c;可以帮助用户快速定位问…

1. OpenAI⼤模型⽣态

OpenAI⼤模型⽣态并不只有⼀个模型&#xff0c;⽽是提供了涵盖⽂本、代码、对话、语⾳、图像领域的⼀系列模型。 基本介绍 语⾔类⼤模型&#xff1a;GPT-3、GPT-3.5、GPT-4系列模型。并且&#xff0c;OpenAI在训练GPT-3的同时&#xff0c;训练了参数不同、复杂度各不相同的A、…

【Vue】指令之显示切换,属性绑定

Vue指令【2】 显示切换与属性绑定v-show指令v-if指令v-bind指令 显示切换与属性绑定 v-show指令 作用&#xff1a;根据真假切换元素的显示状态 指令后的内容最终都会解析为布尔值数据改变之后&#xff0c;对应元素的显示状态会同步更新 语法&#xff1a; <div id"…

[NOIP2013 提高组] 货车运输

[NOIP2013 提高组] 货车运输 题目背景 NOIP2013 提高组 D1T3 题目描述 A 国有 n n n 座城市&#xff0c;编号从 1 1 1 到 n n n&#xff0c;城市之间有 m m m 条双向道路。每一条道路对车辆都有重量限制&#xff0c;简称限重。 现在有 q q q 辆货车在运输货物&#x…

c++ STL less 的视角

c less 函数在不同的地方感觉所起的作用是不一样的&#xff0c; 这中间原因是 less 的视角不一样&#xff0c; 下面尝试给出解释下&#xff0c; 方便记忆 1、 左右视角 符合 排序sort less(value, element&#xff09; less 表示一种 “符合关系“&#xff0c; 表示sort 后…

关于Ubuntu下docker-mysql:ERROR 2002报错

报错场景&#xff1a; mysql容器创建好后登录mysql时即使密码正确也是报出下方提示&#xff1a; 原因是在创建mysql容器在创建时本地目录缺失&#xff0c; 先去自建一个目录&#xff0c;例如&#xff1a; /opt/my_sql 正确完整目录如下&#xff1a; docker run --namemys…

一个升级迁移11g到19c使用xtts遇到的小问题

oracle11.2.0.4到19.21 1.系统权限和对象权限&#xff0c;由于大小写对象名问题&#xff0c;如果使用expdp方式迁移可能存在丢失 迁移后需比对对象、权限&#xff0c;避免遗漏 set pagesize 0 set long 90000 set feedback off set echo off spool ddl.sql select dbms_meta…