【C++】IO库 && IO流

【C++】IO库 && IO流

📝前言:

这篇文章我们来讲讲IO库 && IO流:

🎬个人简介:努力学习ing
📋个人专栏:C++学习笔记
🎀ZEEKLOG主页 愚润求学
🌄其他专栏:C语言入门基础python入门基础python刷题专栏Linux

文章目录

一,IO库

C语言是面向过程的语言,而C++是面向对象。在C++中,我们的IO也是面向对象的,这个对象也叫做流。对于要输出的目标文件的不同,IO的对象的类型就不同(比如,输出到屏幕和输出到文件的IO类型是不同的)。

C++IO类型设计的是⼀个继承家族,通过继承家族类解决控制台/⽂件/string的IO操作。

在这里插入图片描述

二,IO流

1. 什么是IO流

流是一种抽象概念,表示数据从一个源到目标的流动

  • 输入流:数据从外设流向程序
  • 输出流:数据从程序流向外设

在C++中,我们可以把流看做是一个具有以下特性的对象。

  1. 缓冲区:用来存储数据,避免频繁的与外设交互,提高IO效率
  2. 状态:流对象会维护一个状态标识,用于检测IO操作是否成功
  3. 不同流动方向对应不同的对象:输入流和输出流对应的对象不同
  4. 运算符重载:可以使用<<>>进行输入和输出(方便)
  5. 格式化控制:允许<<>>中对数据进行格式化控制

2. IO流的状态

IO流中的状态用标记位来表示,通过|操作可以链接多个标记位。

四种状态(定义在ios_base中,子类流都是会继承下来的):

  • goodbit表示:流没有错误,对应0001
  • failbit表示:IO操作失败,对应0010
  • eofbit表示:流到达文件结束,对应0100
  • badbit表示:流崩溃了出现了系统级错误,对应1000

其他细节:

  • 如果到达文件结束位置eofbitfailbit都会被置位
  • ⼀个流一旦发生错误,后续的IO操作都会失败,这时需要调用clear()函数来重置流的标记位为1000
  • 出现badbit代表底层系统级错误,clear()也没用,这个流就完全不可用了
  • 在基类ios_base中也提供了很多访问器,让用户可以查看流的状态
    • good():查看goodbit
    • rdstate():返回当前流的所有错误组合的标识(通常是:bad, fail, eof的组合),通过&对应的状态位可以得到具体的状态(不如fail()等方便)
    • setstate(iostate flags):设置流的标记位(即:置为1),setstate(failbit | eofbit)把这两位置为1

示例:

intmain(){ cout << cin.good()<< endl;// 查看 cin 的 goodbitint i; cin >> i;// 故意输入 字符 a 创造错误 cout <<(cin.rdstate()& ios_base::failbit)<< endl;// 看当前流的错误信息 cin.clear();// 重置状态为: 1000// 但是注意:此时字符 a 还在缓冲区没有被读走 cin.get();// 读走 cin 缓冲区的一个字符 cin >> i;// 重新输入 10  cout << i << endl; cout << cin.good()<< cin.bad()<< cin.fail()<< cin.eof()<< endl;return0;}

运行结果:

在这里插入图片描述


如果缓冲区中还残留有多个字符,我们可以用peek()查看缓冲区的第一个字符,然后get出来,直到第一个字符为int时再重新cin

3. IO流的缓冲区

用户的输入并不是直接刷新到外设上,而是先保存在IO流的缓冲区里,当我们刷新缓冲区的时候才会刷新到外设上(实际上是先刷新到内核缓冲区上,但是这设计操作系统)
缓冲区刷新模式分为:满刷新、行筛选、立即刷新(在这里我就不细讲了。)

  • endlflush会立即强制刷新缓冲区
    • endl其实是一个函数,<<对应函数指针会调用对应的函数,而endl里面包括换行和flush操作
  • unitbuf:设置成立即刷新模式

什么时候会触发缓冲区刷新?

  1. 缓冲区满了
  2. 满足刷新模式的条件了
  3. 强制刷新,如flush
  4. 被绑定了,在操作输入流时,绑定的输出流会自动刷新缓冲区

如:默认情况下cincout绑定,所以cin读的时候,会导致cout缓冲区会被刷新
操作:

cin.tie(&cout);// 绑定 cin.tie(nullptr);// 解绑

同步:每次 C++ 流操作前,会先刷新对应的 C 流缓冲区(反之亦然),确保输出顺序一致

关闭同步:

// 关闭标准 C++ 流是否与标准 C 流在每次输⼊/输出操作后同步。 ios_base::sync_with_stdio(false);// 默认是true

关闭以后coutprintf混用的时候,输出顺序就不能保障

4. 标准IO流

不过多讲了,cincout一直在用

  • ostreamistream是不支持拷贝的,只支持移动(外部也不能使用,因为是保护成员)
  • 对于内置类型,可以直接使用<<>>
  • 对于自定义类型,自定义类型要重载<<>>
  • istreamcin对象⽀持转换为bool
    • 即:可以if(cin),如果cin被设置了badbitfailbit,就返回false,如果是goodbit就返回true
  • 其他接口也不讲了,需要的时候再查阅(毕竟也记不完,也没必要硬记)

5. 文件IO流

  • ofstreamostream的派生类,用于输出(写), ifstreamistream的派生类,用于输入(读),fstreamifstreamofstream的派生类,既可以读也可以写
  • 文件流对象可以在构造时打开文件,也可以调用open函数打开文件,打开文件的mode(选项,本质也是标记位,可以用|来组合)有5钟
    • out:写方式打开,默认清空写
    • trunc:清空写
    • app:每次写操作都到末尾写
    • in:只读方式打开
    • ate:打开时把文件指针定位到文件末尾(有点鸡肋,用不到)
    • binary:二进制方式 读 / 写(看和哪个搭配)
  • 注意:因为这些标识符是基类的成员,而iostream又是继承的ios_base在,子类中要使用继承的成员需要指明基类的类域,即:ios_base::out
    (以上的操作和Linux中的系统调用都差不多,因为本来封装的就是系统调用,就不展示寄出用法了)

示例1

下面展示一个,对于一个已有内容的文件,不希望希望清空,然后用seekp()设置文件指针写入指针的位置,来实现任意位置读写的操作。(seekp是写入指针,seekg是读指针)

log.txt

在这里插入图片描述


代码:

intmain(){// 这样打开文件就不会清空,文件指针在起始位置 ofstream outfile("log.txt", ios_base::out | ios_base::in); outfile.seekp(9, ios::cur);// 把指针从当前位置往后移动 9 个位置(以字节为单位) outfile <<"hello"<< endl;return0;}

运行结果:

在这里插入图片描述


可见,文件写指针p本来原来指向1,往后移动9个位置到,然后覆盖写入hello共五个字符,即覆盖写了:\n6,7,共五个字符。

示例2

下面展示一个直接以二进制方式读写来实现图片复制。

intmain(){ ifstream ifs("test.png", ios_base::in | ios_base::binary); ofstream ofs("test_copy.png", ios_base::out | ios_base::binary);int n =0;while(ifs && ofs)// 确保流的状态都是 good 的{char ch = ifs.get(); ofs << ch;++n;} cout << n << endl;return0;}

运行结果:

在这里插入图片描述


对于大部分东西的复制,我们都可以用二进制,直接当一个整体输入和输出。

一定要确保两步都是用binary来的。因为图片的内容不是标准的字符,文本输入和输出中,遇到的一些字符(就如我们cin字符时,输入ctrl + z)可能会标记faileof,导致流失效,图片不能复制完全。

6. string IO流

  • string IO流是一种在内存中处理字符串的流类,它允许你像操作文件流一样操作字符串,即可以使用<<>>(和操作文件的方法一样)
  • ostringstreamstring的写入流,istringstreamstring的读出流
  • stringstreamostringstreamistringstream的派生类,既可以读也可以写【这个更好用,因为我们对字符串的读写控制没文件要求怎么高】
  • stringstream系列底层维护了⼀个string类型的对象来保存结果
  • string流使用str函数获取底层的string对象

示例1

intmain(){// 输出字符串流 (ostringstream) ostringstream oss; oss <<"Hello "<<32<<" world!";// 会把 32 当字符 string str = oss.str();// 获取字符串 cout << str << endl;// 输入字符串流 (istringstream) istringstream iss("100 200");// 用"100 200"构造 iss底层的stringint a, b; iss >> a >> b;// >> 会以空格为分隔符 cout << a + b << endl;// 输入输出字符串流 (stringstream) stringstream ss; ss <<"3.14";double pi; ss >> pi;// 从 ss 流中读入 3,14 然后给了pi cout << pi *2<< endl;return0;}

2. 示例2

对于自定义类型,需要自定义类型重载<<

classDate{public:friend ostream&operator<<(ostream& out,const Date& d);Date(int y,int m,int d):_year(y),_month(m),_day(d){}private:int _year;int _month;int _day;}; ostream&operator<<(ostream& out,const Date& d){ out << d._year <<"/"<< d._month <<"/"<< d._day;return out;}intmain(){ stringstream ss; Date date1(2025,6,3); ss << date1 <<" hello world!"<< endl; cout << ss.str()<< endl;return0;}

运行结果:


🌈我的分享也就到此结束啦🌈
要是我的分享也能对你的学习起到帮助,那简直是太酷啦!
若有不足,还请大家多多指正,我们一起学习交流!
📢公主,王子:点赞👍→收藏⭐→关注🔍
感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!

Read more

Flutter 组件 riverpod_signals 的适配 鸿蒙Harmony 实战 - 驾驭双剑合璧状态架构、实现鸿蒙端强依赖注入与细粒度刷新深度融合方案

Flutter 组件 riverpod_signals 的适配 鸿蒙Harmony 实战 - 驾驭双剑合璧状态架构、实现鸿蒙端强依赖注入与细粒度刷新深度融合方案

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 riverpod_signals 的适配 鸿蒙Harmony 实战 - 驾驭双剑合璧状态架构、实现鸿蒙端强依赖注入与细粒度刷新深度融合方案 前言 在鸿蒙(OpenHarmony)生态的极繁数字化政务底座、大型分布式供应链管理系统以及对架构严密性与交互流畅度有“双重严苛审计要求”的各类企业级应用开发中,“架构的解耦深度与 UI 的响应广度”是衡量软件成熟度的两把关键标尺。面对包含上百个全局服务(Service)与数千个高频局部刷新节点(Widget)的复杂资产体系。如果全量使用 Riverpod 的 Consumer 监听,可能会在大型列表中产生不必要的树扫描开销;而如果仅使用 Signals,又会因为缺乏完善的依赖注入(DI)机制。导致业务逻辑流的组织变得松散且难以维护。 我们需要一种“顶级架构对齐、局部响应闭环”的融合艺术。 riverpod_signals 是一套专注于将

By Ne0inhk
数据库迁移 TCO 全景账本:MySQL 替代中的隐性成本与工程化工具链实测

数据库迁移 TCO 全景账本:MySQL 替代中的隐性成本与工程化工具链实测

文章目录 * 前言:决策者的“隐形焦虑”与迁移困局 * 一、 TCO 全景账本:隐性成本都藏哪儿了? * 1. 成本结构深度对比 * 2. 效率数据实测 * 二、 迁移主力军:KDTS 自动化迁移深度解析 * 1. 核心黑科技:智能映射与兼容 * 2. 实战演示:命令行高效迁移 * 三、 零停机保障:KFS 双轨增量同步与“后悔药” * 1. 架构原理:双轨运行,进退自如 * 2. 实战演示:KFS 任务配置与验证 * 四、 最后一公里:KDFS 数据校验定心丸 * 五、 结语:让迁移成为一次“无感”的升级 前言:决策者的“隐形焦虑”与迁移困局 在数据库国产化替代(

By Ne0inhk
Spring Cloud 高并发订单服务实战:从创建流程优化到 Seata 分布式事务落地(附代码 + 架构图)

Spring Cloud 高并发订单服务实战:从创建流程优化到 Seata 分布式事务落地(附代码 + 架构图)

前言         做电商或者供应链系统的同学肯定都遇到过这样的痛点:大促期间,数万用户同时下单,订单服务瞬间被打垮,出现接口超时、数据库锁等待、库存超卖;更头疼的是,订单创建需要跨订单服务、库存服务、支付服务三个模块,一旦某个环节出错,就会出现 “订单创建成功但库存没扣减” 或者 “库存扣减了但支付失败” 的一致性问题。         这些问题不是靠简单调优 JVM 或者加个缓存就能解决的,而是需要一套高并发优化体系 + 分布式事务解决方案的组合拳。         本文就以订单服务为核心场景,从实战角度出发,先讲清楚高并发下订单创建流程的核心优化点(限流、削峰、缓存、防超卖),再深入讲解 Seata 分布式事务的原理和三种模式,最后通过完整的代码案例,演示如何在 Spring Cloud 体系中落地 Seata,彻底解决跨服务的事务一致性问题。         全文都是干货,包含4 张核心 SVG 架构图、完整的代码片段、实际开发中的坑和解决方案,建议先收藏,再慢慢看。 1.

By Ne0inhk
Java 部署:K8s Deployment 部署 Spring Boot 应用

Java 部署:K8s Deployment 部署 Spring Boot 应用

👋 大家好,欢迎来到我的技术博客! 📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。 🎯 本文将围绕Java部署这个话题展开,希望能为你带来一些启发或实用的参考。 🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获! 文章目录 * Java 部署:K8s Deployment 部署 Spring Boot 应用 🚀 * 1. 创建一个简单的 Spring Boot 应用 💻 * 1.1 项目结构 * 1.2 编写控制器 * 1.3 配置 Actuator * 1.4 本地测试 * 2. 构建 Docker 镜像 🐳 * 2.1 编写 Dockerfile * 2.2 构建 JAR

By Ne0inhk