初识C++ · IO流

news2024/9/22 10:23:13

前言:

IO流,启动!因笔者对于IO流的理解不是很深刻,所以这里进行简单的介绍即可。


1 IO流

IO流是我们从学习C++开始就一直会使用的东西,我们先了解一下C++IO流的一套继承体系:

整个IO体系的基类是ios_base,看IO的源码的时候也有所体现,这里也用到了菱形虚拟继承,istream和ostream继承了ios,iostream继承了ostream istream,后面的分别是文件流 字符串流。

我们平常使用的iostream里面,cout cerr clog都是输出,使用起来是没有差别的,不过是一个输出日志 一个输出错误码,它们是底层机制有区别,这里了解一下即可:

int main()
{
	int a = 2;
	cout << a << endl;
	cerr << a << endl;
	clog << a << endl;
	return 0;
}

对于cout而言,一般是输出的窄字符->narrow char ,我们平时使用的字符基本上都是窄字符,用utf8表示的,当然也有宽字符:

同理,也有wcerr wlog,我们目前都还用不上,涉及到utf16的时候,说不定就会有所接触了。

根据文档介绍,对象都是通过标准的输出流面向窄字符流输出的,不妨简单描述一点就是,输入输出是通过字符流完成的。比如以文件的形式读取的时候,都是先转换为字符串,然后再读进去。

现在思考一个问题,cin>>的返回值是什么?为什么可以使用while来判断

文档也没有过多的介绍,这里cin>>能作为返回值实际上是调用了istream类的函数:

operator bool,检查到输出了类似于eof的这种标志,就返回了false,while循环就结束了。

正常输入的时候,是怎么判断流输入正常的呢?

调用的是istream的这四个成员变量,good eof fail bad:

对于good 来说,检查流是不是正常的,这个我们一般不用管,对于eof来说,是文件的标志结尾,我们也不用管,对于fail来说,是有没有基本的逻辑错误,比如读取的是整型但是输入的是char,bad就更不用管了,一般严重错误的时候才会设置,所以我们实际要关心的是fail,我们可以打印看看:

int main()
{
	int a = 0;
	cout << cin.good() << endl;
	cout << cin.eof() << endl;
	cout << cin.fail() << endl;
	cout << cin.bad() << endl;

	cin >> a;

	cout << cin.good() << endl;
	cout << cin.eof() << endl;
	cout << cin.fail() << endl;
	cout << cin.bad() << endl;
	return 0;
}

正常的打印结果就是1 0 0 0 ,那么我如果输入字符呢?

可以看到good 和 fail被设置为了相反的,说明输入不正常。

面临这种情况,我们就要想办法把字符去掉,这些标志也要重新设置,如果不重新设置:

a也打印不出来我们想要的值,重新设置的函数为clear,去掉字符就get一下就可以了:

int main()
{
	int a = 0;
	cout << cin.good() << endl;
	cout << cin.eof() << endl;
	cout << cin.fail() << endl;
	cout << cin.bad() << endl;

	cin >> a;

	cout << cin.good() << endl;
	cout << cin.eof() << endl;
	cout << cin.fail() << endl;
	cout << cin.bad() << endl;
	
	cin.clear();
	cin.get();

	cin >> a;
	cout << a << endl;
	return 0;
}

同理,如果有多个字符,咱么多get一下就可以了。

这是在IO流的cin里面要注意的事。

这里简单提一下,在竞赛中,如果io的输入输出过多了,就会影响效率的,因为C++兼容C语言,所以C语言有自己的缓冲区,C++也有自己的缓冲区,输入输出的时候,不同的缓冲区之间有绑定关系,即自己的事干完了还要看别的缓冲区有没有完事儿,那么呢,缓冲区刷新才能让里面的东西出去是吧?如果我不设置刷新的标志,比如换行,是不是C++的打印就在C语言之前了呢?

int main()
{
	printf("a");
	cout << " a " << endl;
	printf("\n");
	return 0;
}

这里是不会的,因为编译器作了相关处理。

默认的是cin 绑定 cout cerr ,IO的输入输出一多,就会导致我干完了我还要等你,所以解除绑定关系可以高效率,代码如下:

ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);

sync的意思是同步,tie的默认参数:

给tie空指针就是说,谁也不绑定了,我自己单干,这样效率会高一点。


2 文件流

文件流和C语言的文件流使用起来是方面很多的,这时IO流的一个优势,具体请看下文。

首先先来了解一下fstream的构造:

文件流类的构造的默认参数有了,我们就不用写,其中ios_base::in,是基类的,但是因为继承下来了,我们也可以使用fstream的in,但是没必要,然后:

根据文件的不同的读写模式可以实现不同模式的读取,默认是文本的形式读取的,这里面的write就是C语言里面的fwrite,默认的写是覆盖写,想要追加写就使用app写,文件流所在的头文件是fstream:

int main() 
{
	std::ofstream ofs("test.txt");
	ofs << "xxxxxxxxxxxxxx";
	return 0;
}

写进去,没有就创建,改写进去的内容默认覆盖:

int main() 
{
	std::ofstream ofs("test.txt", ofstream::out | ofstream::app);
	ofs << "111";

	return 0;
}

这样是追加写。

那么如何读取一个图片呢?使用istream进行读取即可;

int main()
{
	ifstream ifs("D:\\C++\\数据结构.jpg", ifstream::in | ifstream::binary);
	char c = ifs.get();
	int n = 0;
	while (ifs.good()) {
		++n;
		c = ifs.get();
	}
	cout <<n<<endl;
	return 0;
}

使用ifstream流读取即可,其中ifstream是读取 ostream是写入 fstream是既可以读也可以写。

那么理论上来说,复制图片也是可以的,这个小实验就交给同学们完成了。

那么今天的重点就要来了,我们如何将一个类的数据写到文件里面?在C语言的章节,我们都是写入的一些整型,今天写入自定义类型:

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 ServerInfo
{
	char _ip[32];
	//string _ip;
	int _port;
	Date _date;
};

struct ConfigManager
{
public:
	ConfigManager(const char* filename = "test.txt")
		:_filename(filename)
	{}

private:
	string _filename; // 配置文件
};

用到的三个类如上,我们分为二进制的读写和文本文本读写来看,首先是二进制读写:

二进制的读写是最简单的:

	void WriteBin(const ServerInfo& info)
	{
		ofstream ofs(_filename, ios_base::out | ios_base::binary);
		ofs.write((const char*)&info, sizeof(ServerInfo));
	}

	void ReadBin(ServerInfo& info)
	{
		ifstream ifs(_filename, ios_base::in | ios_base::binary);
		ifs.read((char*)&info, sizeof(info));
	}

整体的思路是将结构体的地址转换为char*的地址,然后一个字符一个字符的读取就行了。

但是二进制面临有地址的读写是会出问题的,因为结构体里面的数据有成员变量,string这种,如果是string,指向的空间我们是没有拷贝的,拷贝的是那个地址,所以如果使用二进制的读写string vector这种就会报错,如果是文本操作就不会。

在这里IO流的优点就体现出来了,如果是C语言还要将string转为字符串,但是IO流这里可以直接写入:

void WriteText(const ServerInfo& info)
{
	ofstream ofs(_filename);
	ofs << info._ip << " " << info._port << " " << info._date;
}

void ReadText(ServerInfo& info)
{
	ifstream ifs(_filename);
	ifs >> info._ip >> info._port >> info._date;
}

因为重载了 << >>,就不用单独转换了。



3 字符串流

字符串流用在序列化和反序列化,就是转成字符串说什么的,

同样,stringstream是两者的集合,所在的头文件是sstream,使用的时候可以将字符串转化为结构体信息也可以将结构体信息转换为字符串,这里看个代码就行:


struct ChatInfo
{
	string _name; // 名字
	int _id;      // id
	Date _date;   // 时间
	string _msg;  // 聊天信息
};
int main()
{
	// 结构信息序列化为字符串
	ChatInfo winfo = { "张三", 135246, { 2022, 4, 10 }, "晚上一起看电影吧" };
	ostringstream oss;
	oss << winfo._name << " " << winfo._id << " " << winfo._date << " " << winfo._msg;
	string str = oss.str();
	cout << str << endl << endl;
	// 字符串解析成结构信息
	ChatInfo rInfo;
	istringstream iss;
	iss.str(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;
}

给空格是因为方面后面好读取,因为没有空格读取的话后面读出来看不懂的,也算是一个分隔符了。

这部分校招方面考的很少,所以咱们了解一下就行了。


感谢阅读!

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

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

相关文章

ArkTs基础语法

ArkTs基础语法 声明变量声明常量声明自动类型推断 类型基础类型NumberBooleanString 引用类型VoidObjectArrayEnumUnionAliases 语句if语句switch语句条件表达式 ?:for语句for of语句while语句do while语句breakcontinuethrow和try catch finally语句 函数函数声明可选参数Res…

MySQL中的锁事

一、概述 锁是计算机在执行多线程或线程时用于并发访问同一共享资源时的同步机制&#xff0c;MySQL中的锁是在服务器层或者存储引擎层实现的&#xff0c;保证了数据访问的一致性与有效性。 事务的隔离性是由的锁来实现。 二、MySQL并发事务访问的问题 我们已经知道事务并发…

day-39 矩阵中的最大得分

思路 动态规划。利用一个二维数组记录对应位置可以达到的最高得分&#xff08;位置&#xff08;0,0&#xff09;不可能&#xff09;&#xff0c;然后找出最大值即可&#xff08;如果除了&#xff08;0,0&#xff09;上的值其他值都一样&#xff0c;则返回任意一个即可&#xff…

Python 3 入门基础知识 之数据容器及用法【2】 推荐

前面关于python的下载安装、如何定义变量&#xff0c;基本的数据类型&#xff0c;以及if条件语句、for循环语句&#xff0c;部分运算都进行了梳理总结。参考&#xff1a;Python 3 入门基础知识【1】数据类型 安装下载 推荐-CSDN博客 这里回顾一下python的数据容器基础知识&…

智能换热:图扑智慧供热可视化管理平台

图扑搭建智慧供热可视化管理平台&#xff0c;通过实时监控和数据分析提升运营效率&#xff0c;实现智能化管理&#xff0c;保障系统稳定与高效运行。

深挖Redis分布式缓存:你还在为缓存架构感到困惑吗?灵办AI为你揭开文献背后的秘密!

文章目录 1 灵办AI插件2 翻译~外文文献3 解释~文献标题分析4 文档解析~文献总结5 搜索~全网搜索总结6 总体评价~文献代码分析总结 本文将引用 Research and Application of Distributed Cache Based on Redis [1] 外文文献解读为案例进行剥削&#xff0c;进而提高对 Redis的分布…

相机光学(三十五)——三刺激值

0.参考链接 [1]三刺激值 [2]色差仪CIERGB和CIEXYZ光谱三刺激值区别 1.三刺激值的由来 根据杨-亥姆霍兹的三原色理论&#xff0c;色的感觉是由于三种原色光刺激的综合结果。在红、绿&#xff0c;蓝三原色系统中&#xff0c;红。绿、蓝的刺激量分别以R、G、B表示之。由于从实际…

安装开源软件ChatALL(齐叨)来聚合各大人工智能工具

安装开源软件ChatALL&#xff08;齐叨&#xff09;来聚合各大人工智能工具 前言 如果你跟我一样无论遇到什么问题都要询问人工智能&#xff0c;并且至少同时用4-5个公司的人工智能&#xff0c;选择一个最中意的结果 以前我都会用Chrome浏览器打开4个窗口&#xff0c;每个问题…

c语言中比较特殊的输入格式

目录 一.%[ ] 格式说明符 1.基本用法 (1)读取字母字符: (2)读取数字字符: (3)读取所有字符直到遇到空格: (4)读取直到换行符: 2.使用范围和组合: 3.^ 取反操作 4.注意事项 (1). 字符范围的正确表示 (2). 避免字符集中的特殊字符冲突 (3).避免空字符集 (4). 输入长…

C++竞赛初阶L1-11-第五单元-for循环(25~26课)510: T454422 均值

题目内容 给出一组样本数据&#xff0c;计算其均值。 输入格式 输入有两行&#xff0c;第一行包含一个整数&#xff0c;表示样本容量 n。 第二行包含 n 个浮点数 ai​&#xff0c;代表各个样本数据。 输出格式 输出一行&#xff0c;包含一个浮点数&#xff0c;表示均值。 …

TikTok爆款盘点-哪些产品会更受欢迎

海外短视频兴起&#xff0c;TikTok成为了国内企业出海最成功的APP。TikTok现在不仅是一个娱乐社交平台&#xff0c;也是一个强大的电商平台。如果出海卖家在选品上好好下功夫&#xff0c;利用TikTok这个营销工具&#xff0c;在海外也能获得不小的收益。 那么&#xff0c;TikTok…

网络协议十 应用层 SPDY / HTTP2 / QUIC / HTTP3

一 HTTP1.1 的不足 二 SPDY 协议 三 HTTP2 也只是需要在 server 端配置&#xff0c;不需要改动 服务器的代码。 HTTP2 可以看成是 将 SPDY 和 HTTP 融合在一起的改动 上面image sprites 的概念 HTTP2的问题--对头阻塞 和 握手延迟问题 引出的 QUIC 技术 由于传输层用的 TC…

node20+版本下hexo部署报错失败的解决办法

最近升级了node.js的版本&#xff0c;升到了最新的稳定版本v20.16.0&#xff0c;结果发现在该版本下hexo部署报错失败。本文记录了node20版本下hexo部署报错失败的解决办法。 一、报错信息 执行hexo的deploy部署命令 hexo d具体报错信息如下 INFO Deploying: git INFO Cl…

【大模型系列】更像人类行为的爬虫框架

随着大规模模型技术的兴起&#xff0c;我们可以看到百模大战、各种智能体、百花齐放的应用场景&#xff0c;那么作为一名前端开发者&#xff0c;以前端的视角&#xff0c;我们应当如何积极做好技术储备&#xff0c;开拓技术视野&#xff0c;在智能体时代保持一定的竞争力呢&…

webpack打包可视化分析之--webpack-bundle-analyzer

在开发一些项目的时候&#xff0c;有时候有些旧的框架项目用的webpacke打包慢&#xff0c;打包出来的包文件大&#xff0c;然而我们想要对它进行优化分析&#xff0c;有些旧的项目可能在不断迭代的过程中&#xff0c;有些模块功能改造或者有些需求变化&#xff0c;有些新需求模…

python的warnings.filterwarnings(“ignore“)

在python中运行代码经常会遇到的情况是——代码可以正常运行但是会提示警告&#xff0c;如果想要去掉这些警告&#xff0c;可以使用python的warnings.filterwarnings(“ignore”)函数。 代码&#xff1a; import warnings warnings.filterwarnings(ignore)看一下这个函数&…

【学习笔记】数据结构(五)

多维数组和广义表 文章目录 多维数组和广义表5.1 数组的定义5.2 数组的顺序表示和实现5.3 矩阵的压缩存储5.3.1 特殊矩阵5.3.2 稀疏矩阵三元组顺序表 (Triplet Representation) - 有序的双下标法行逻辑链接的顺序表十字链表法 5.4 广义表的定义5.5 广义表的存储结构5.6 m元多项…

mysql与Python交互

mysql数据库基本操作&#xff1a; [rootm ~]# tar -xf mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz 解压压缩包 [rootm ~]# ls anaconda-ks.cfg mysql-5.7.44-linux-glibc2.12-x86_64 mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz [rootm ~]# cp -r mysql-5.7.44-linu…

【myz_tools】Python库 myz_tools:Python算法及文档自动化生成工具

写在前面 本来最开始只是单纯的想整理一下常用到的各类算法&#xff0c;还有一些辅助类的函数&#xff0c;方便时间短的情况下快速开发。后来发现整理成库更方便些&#xff0c;索性做成库&#xff0c;通过pip install 直接可以安装使用 关于库 平时见到的各类算法大多数还是…

volatile 浅谈

在Java中&#xff0c;volatile 关键字是一种轻量级的同步机制&#xff0c;它用于确保变量的可见性和有序性&#xff0c;但不保证原子性。当我们说 volatile 屏障时&#xff0c;我们实际上是在讨论 volatile 变量如何影响Java内存模型&#xff08;JMM&#xff09;中的操作重排序…