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;
		else
			return 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流来输入输出,拜拜!


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

金三银四_程序员怎么写简历_写简历网站

你们在制作简历时,是不是基本只关注两件事:简历模板,还有基本信息的填写。 当你再次坐下来更新你的简历时,可能会发现自己不自觉地选择了那个“看起来最好看的模板”,填写基本信息,却没有深入思考如何使简历更具吸引力。这其实是一个普遍现象:许多求职者仍停留在传统简历…

【Unity3D小技巧】Unity3D中UI控制解决方案

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 在开发中总是会控制UI界面&#xff0c;如何优雅的控制UI界面是…

12.1 主成分分析原理(PCA)

主成分分析步骤如下&#xff1a; 设有条维数据 1. 将原始数据按列组成行列矩阵 &#xff1b; 2. 将矩阵 的每一行进行零均值化&#xff1b; 3. 求出协方差矩阵&#xff1b; 4. 求出协方差矩阵的特征值及对应的特征向量&#xff1b; 5. 将特征向量按对应特征值大小从上到…

富文本编辑器CKEditor4简单使用-04(跟源码设置image2插件图片的默认宽高等相关配置)

富文本编辑器CKEditor4简单使用-04&#xff08;跟源码设置image2插件图片的默认宽高等相关配置&#xff09; 1. 前言1.1 CKEditor4快速上手 2. CKEditor4的一般配置2.1 工具栏相关2.2 插件相关2.3 设置界面宽高等 3. CKEditor4的图片相关配置3.1 关于增强的图像插件的必要配置3…

洛谷 P3817 小A的糖果

题目描述 小 A 有 n 个糖果盒&#xff0c;第 i 个盒中有 a【i​】 颗糖果。 小 A 每次可以从其中一盒糖果中吃掉一颗&#xff0c;他想知道&#xff0c;要让任意两个相邻的盒子中糖的个数之和都不大于 x&#xff0c;至少得吃掉几颗糖。 输入格式 输入的第一行是两个用空格隔…

nop-entropy可逆计算入门(1)

第1步&#xff1a;从大佬的gitee&#xff1a;https://gitee.com/canonical-entropy/nop-entropy下载源码&#xff0c;进行本地编译&#xff0c;具体编译看项目下的readme,想偷懒的可以下载我编译后的jar&#xff0c;放到自己的maven仓库 https://pan.baidu.com/s/1p9MOh40MJ2m…

unity 拖入文件 窗口大小

目录 unity 拖入文件插件 设置窗口大小 unity 拖入文件插件 GitHub - Bunny83/UnityWindowsFileDrag-Drop: Adds file drag and drop support for Unity standalong builds on windows. 设置窗口大小 file build

【kubernetes】集群网络(二):Flannel的VxLan、Host-GW模式

文章目录 1 Pod的IP地址的分配2 CNI3 Flannel3.1 Flannel的安装3.2 VxLan3.3 Host-GW 4 总结 1 Pod的IP地址的分配 当节点上只安装了docker&#xff0c;则会用veth pairdocker0实现单个节点上容器之间的通信&#xff0c;并且这些容器都在同一个IP段&#xff0c;如果不修改&…

挑战杯 LSTM的预测算法 - 股票预测 天气预测 房价预测

0 简介 今天学长向大家介绍LSTM基础 基于LSTM的预测算法 - 股票预测 天气预测 房价预测 这是一个较为新颖的竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng-senior/postgraduate 1 基于 Ke…

STM32F407移植OpenHarmony笔记8

继上一篇笔记&#xff0c;成功开启了littlefs文件系统&#xff0c;能读写FLASH上的文件了。 今天继续研究网络功能&#xff0c;让控制台的ping命令能工作。 轻量级系统使用的是liteos_m内核lwip协议栈实现网络功能&#xff0c;需要进行配置开启lwip支持。 lwip的移植分为两部分…

8、应急响应-战前溯源反制主机蜜罐系统HFishHIDSElkeidWazuh

用途&#xff1a;个人学习笔记&#xff0c;欢迎指正 目录 背景&#xff1a; 一、潮源反制-平台部署-蜜罐-Hfish 二、溯源反制-平台部署-HIDS-Wazuh 三、溯源反制-平台部署-HlDS-Elkeid-hub 背景&#xff1a; 攻击者对服务器存在着各种威胁行为&#xff0c;作为安全人员&am…

SpringBoot security 安全认证(二)——登录拦截器

本节内容&#xff1a;实现登录拦截器&#xff0c;除了登录接口之外所有接口访问都要携带Token&#xff0c;并且对Token合法性进行验证&#xff0c;实现登录状态的保持。 核心内容&#xff1a; 1、要实现登录拦截器&#xff0c;从Request请求中获取token&#xff0c;从缓存中获…

【自然语言处理】P2 PyTorch 基础 - 张量

目录 安装 PyTorch张量创建张量操作张量索引、切片、联合操作 CUDA张量 本系列博文我们将使用 PyTorch 来实现深度学习模型等。PyTorch 是一个开源的、社区驱动的深度学习框架。拥有强大的工具和库生态系统&#xff0c;包含 TorchVision&#xff08;用于图像处理&#xff09;、…

2024 IC FPGA 岗位 校招面试记录

引言 各位看到这篇文章时&#xff0c;24届校招招聘已经渐进尾声了。 在这里记录一下自己所有面试&#xff08;除了时间过短或者没啥干货的一些研究所外&#xff0c;如中电55所&#xff08;南京&#xff09;&#xff0c;航天804所&#xff08;上海&#xff09;&#xff09;的经…

图像去噪——SpatiallyAdaptiveSSID网络推理测试(详细图文教程)

SpatiallyAdaptiveSSID 是一种有效的图像去噪方法&#xff0c;它通过自适应地处理不同区域的噪声&#xff0c;能够在保持图像细节的同时&#xff0c;有效地去除噪声。 目录 一、SpatiallyAdaptiveSSID网络简介二、源码包准备2.1 测试集2.2 模型权重文件 三、测试环境四、推理测…

【Python-环境搭建】

Python-环境搭建 ▼ Python安装► 进入Python官网 地址如下 [Python官网](https://www.python.org/)► Python安装向导对话框► 测试是否安装成功 ▼ PyCharm 安装► Pycharm的下载和安装 ▼► 开始在 Windows 上使用 Python&#xff08;初学者&#xff09; ▼ Python安装 ► …

Web3生态系统:构建去中心化的数字社会

随着科技的飞速发展&#xff0c;我们正处在迈向数字未来的道路上&#xff0c;而Web3生态系统则成为这一变革的中心。不仅仅是技术的演进&#xff0c;Web3代表着对传统互联网体系的颠覆&#xff0c;致力于构建一个去中心化的数字社会。本文将深入探讨Web3的核心特征、对金融、社…

2024年美赛B题思路分析 - 搜索潜水器

# 1 赛题 问题B&#xff1a;搜索潜水器 总部位于希腊的小型海上巡航潜艇&#xff08;MCMS&#xff09;公司&#xff0c;制造能够将人类运送到海洋最深处的潜水器。潜水器被移动到该位置&#xff0c;并不受主船的束缚。MCMS现在希望用他们的潜水器带游客在爱奥尼亚海底探险&…

MySQL中where和having的区别

前言 数据库中的 WHERE 和 HAVING 子句在 SQL 查询中扮演着关键的角色&#xff0c;帮助我们有效地筛选和过滤数据。这两个子句虽然都用于限定结果集&#xff0c;但它们的应用场景和操作对象存在明显的区别。在理解和运用这两个子句的过程中&#xff0c;我们能够更灵活地进行数据…

MySql主从同步,同步SQL_ERROR 1032解决办法

1.登录从库 mysql -u root -p 2.输入命令查看状态 SHOW SLAVE STATUS\G; 3.找到对应的错误数据位置 Slave_IO_Running: YesSlave_SQL_Running: NoReplicate_Do_DB: app_push_centerReplicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Tabl…