Hello大家好!很高兴我们又见面啦!给生活添点passion,开始今天的编程之路!

我的博客:<但凡.

我的专栏:《编程之路》、《数据结构与算法之美》、《C++修炼之路》、《Linux修炼:终端之内 洞悉真理》

感谢你打开这篇博客!希望这篇博客能为你带来帮助,也欢迎一起交流探讨,共同成长。

目录

1、C++中的IO库

2、IO流状态

3、管理输出缓冲区

4、标准IO流        

5、文件IO流

6、string IO流


 

1、C++中的IO库

        C++不仅支持从控制台读取数据,还支持从设备中读取数据和向设备中写入数据的IO操作,设备可以是文件、控制台窗口等。 

        C++中的IO库是通过一个庞大的继承体系来实现的。这个套体系包含了标准IO流,文件IO流,stringIO流等等。也就是说,我们之前使用的都是标准IO流,从控制台读取字符。但实际上还支持从文件读取,对string字符串,对宽字符进行IO操作。

2、IO流状态

        在IO的过程中可能会出现各种错误,IO流对象中给了四种状态标识错误。      

         默认都是good状态,eofbit表示读到了文件末尾,badbit表示系统级错误,如不可恢复的读写错误,通常情况下,badbit⼀旦被设置了,流就无法再使用了。failbit表示⼀个逻辑错误,如期望读取⼀个整形,但是却读取到⼀个字符,failbit被设置了,流是可以恢复的,恢复以后可以继续使用。

        我们在cin变量的时候,如果我们的变量是int类型,但是我们输入的是一个字符,那么这时候就会标识为failbit:

#include<iostream>
using namespace std;int main()
{int i = 0;cin >> i;//输入一个字符cout << cin.good() << endl;cout << cin.eof() << endl;cout << cin.fail() << endl;cout << cin.bad() << endl;return 0;
}

输出结果:

        那么这个时候,我们就得想办法恢复状态:

#include <iostream>
using namespace std;int main() {int i = 0;cin >> i; // 输入一个字符(比如 'x1')cout << cin.good() << endl;  // 0(false)cout << cin.eof() << endl;   // 0(false)cout << cin.fail() << endl;  // 1(true)cout << cin.bad() << endl;   // 0(false)if (cin.fail()) {cin.clear(); // 必须先清除错误状态,否则后续操作无效// 清除所有非数字字符(包括换行符)char ch;while (cin.get(ch) && !(ch >= '0' && ch <= '9')) {cout << ch;}// 如果读取到数字,放回缓冲区供下一次 cin >> i 读取if (ch >= '0' && ch <= '9') {cin.putback(ch);//重新放回到输入流中}cout << endl;}//if (cin.fail())
//{
//    // clear可以恢复流状态位goodbitcin.clear();
//    // 我们还要把缓冲区中的多个字符都读出来,读到数字停下来,否则再去cin >> i还是会失败//    char ch = cin.peek();
//    while (!(ch >= '0' && ch <= '9'))
//    {
//        ch = cin.get();
//        cout << ch;
//        ch = cin.peek();
//    }
//    cout << endl;
//}cout << cin.good() << endl;  // 1(true)cout << cin.eof() << endl;   // 0(false)cout << cin.bad() << endl;   // 0(false)cout << cin.fail() << endl;  // 0(false)cin >> i; // 现在可以正常读取数字cout << i << endl;return 0;
}

输出结果:

3、管理输出缓冲区

         在输出的时候,我们的结果不是直接输出到控制台的,而是先输出到内存中的缓冲区。也就是说,操作系统可能会把多个输出操作合并成一个输出操作。不论是Windows系统还是Linux系统都是这样,我们可以验证一下:

#include <iostream>
#include<windows.h>
using namespace std;int main() {cout << "test1" << endl;cout << "test2" << endl;cout << "test3" << endl;cout << "test4" << endl;Sleep(5);//系统休眠五秒return 0;
}

         我们执行这串代码,发现,在执行之后,控制台窗口光标闪烁大约五秒,之后一次性输出了所有的字符串。那么在这五秒中,这些字符串就在缓冲区中存放着。

        那么为什么会这样设计呢?因为设备的IO操作通常是很耗时的,允许操作系统将多个输出操作组合为单一的设备写操作会带来很大的性能提升。

         每次触发缓冲区刷新,我们缓冲区的内容就会输出到控制台或者文件中。那么什么情况下会触发缓冲区刷新呢?第一,程序正常结束;第二缓冲区满了;第三,当输出操作符endl或者flush会立即刷新缓冲区;第四,我们使用了操作符unitbuf设置流的内部状态没来清空缓冲区,cerr设置了unitbuf,所以cerr输出都是立即刷新的;第五,一个输出流关联到另一个流时,当这个流被读写时,输出流会立即刷新缓冲区。

        我们详细说一下第五条。第五条是通过tie来实现的,比如,默认情况下cin和cout是绑定在一起的所以说当我们cin时,会刷新cout的缓冲区。我们也可以手动绑定cin和其他的东西。在竞赛的时候,我们有时会关闭C++和C在每次输入输出后同步,解绑cin和cout关联绑定的其他流。这些操作本质上都是为了提升效率。

ios_base::sync_with_stdio(false);//关闭C流与C++流同步
//解绑cin和cout关联绑定的其他流
cin.tie(nullptr);
cout.tie(nullptr);

使用案例: 

#include<iostream>
#include<fstream>
using namespace std;
void func(ostream& os)
{os << "hello world";os << "hello C++";system("pause");//os << endl;//os << flush;//int i;//cin >> i;os << "hello cat";// "hello cat"是否输出不确定system("pause");
}
int main()
{ofstream ofs("test.txt");//func(cout);// unitbuf设置后,ofs每次写都直接刷新//ofs << unitbuf;// cin绑定到ofs,cin进⾏读时,会刷新ofs的缓冲区// cin.tie(&ofs);func(ofs);return 0;
}

         大家可以测试一下以上代码。

        另外再说一下endl,endl其实是一个函数,endl相比\n的区别就是endl除了换行,还会强制刷新缓冲区。

4、标准IO流        

         这部分就比较熟悉了。C++标准IO流是默认关联到控制台窗口的。cin是istream类型全局对象,cout/cerr/clog是ostream类型的全局对象。内置类型都对这两个类进行了重载,自定义类型粗腰自己重载<<和>>运算符。

        istream的cin对象支持转换为bool值,进行条件逻辑判断。如果读取失败(cin被标识eofbit或falibit)就会返回false。

int a = 0, b = 0;
while (cin >> a >> b)//如果读取失败会返回false,跳出循环
{cout << a << " " << b;
}

5、文件IO流

         文件IO流包含ofstream,ifstream,fstream,其中ofstream是输出文件流,我们可以理解为,现在的输出不是输出到控制台上了,而是输出到文件中。ifstream是输入文件流,可以从文件中读入数据。fstream是ifstream和ofstream的派生类,即可以读也可以写。

        文件IO流提供了非常丰富的文件打开方式,这些文件打开方式通过 | 可以组合起来,搭配出来更多种方式。搭配的方式是比C语言的文件操作更丰富的。

        文件打开方式是通过 std::ios_base 标志位组合实现的,常用的标志位包括:

  • std::ios_base::in:以读取方式打开文件。
  • std::ios_base::out:以写入方式打开文件。
  • std::ios_base::app:以追加模式打开文件,写入内容追加到文件末尾(总是在文件尾)。
  • std::ios_base::ate:打开文件后立即定位到文件末尾。
  • std::ios_base::trunc:如果文件已存在,清空文件内容。
  • std::ios_base::binary:以二进制模式打开文件。

        这些值都是ios_base中定义的成员变量继承下来的,并且他们也是组合的独立二进制位值,需要组合时,可以或到一起。以下是他们可以搭配出的各种方式和C语言打开文件方式的对应。

        对于图片这种非文本文件,我们需要使用二进制打开方式,暴力的把所有的内容都读取出来。

        接下来我们通过代码分别看几个文件打开方式。 

#include<iostream>
#include<fstream>
using namespace std;
int main()
{ofstream ofs("test.txt");ofs.put('x');ofs.write("hello\nworld", 11);//一般使用\nofs << "2222";int x = 3333;ofs << x;ofs.close();ofs.open("test.txt", ios_base::out);//写入文件(覆盖)//或ofs.open("test.txt", ios_base::trunc);ofs.close();ofs.open("test.txt", ios_base::out | ios_base::app);//写入文件(追加)ofs << "555" << endl;//需要注意,如果用out和ate其实会覆盖ofs.open("test.txt", ios_base::in | ios_base::out);//读写文件(不覆盖)ofs << "666" << endl;ofs.close();ofs.open("test.txt", ios_base::in | ios_base::out | ios_base::trunc);//读写文件(覆盖)ofs << "777" << endl;ofs.close();std::fstream file("example.bin", std::ios::in | std::ios::out | std::ios::binary);//二进制模式打开文件return 0;
}

        此外,我们用C++的文件操作实现图片的复制操作。对于图片来说,我们只能使用二进制,暴力的复制。注意在二进制读写时我们不能读写string。因为这时候我们读的实际上是一个指向堆空间的指针,当string对象析构后,这块空间就被释放了。

#include<iostream>
#include<fstream>
using namespace std;
int main()
{// 实现⼀个图⽚⽂件的复制,需要⽤⼆进制⽅式打开读写,第⼀个参数可以给⽂件的绝对路径ifstream ifs("C:\\Users\\nobody\\Desktop\\test.png",ios_base::in | ios_base::binary);ofstream ofs("C:\\Users\\nobody\\Desktop\\test-copy.png",ios_base::out | ios_base::binary);int n = 0;while (ifs && ofs){char ch = ifs.get();ofs << ch;++n;}cout << n << endl;return 0;
}

        需要注意,使用文件IO流时,ifstream和cin的规则类似,都提取到空格或者换行就终止。所以说我们要注意,如果文件中的文本是连成一片的,此时我们使用ifstream提取一个string类型的对象,实际上是把这一片内容去哪都提取走了。 

6、string IO流

        ostringstream是string的写入流,ostringstream是ostream的派生类。istringstream是string的读出流,istringstream是istream的派生类。stringstream是ostringstream和istringstream的派生类,即可以读也可以写。

        我们来看一下案例了解一下:

#include <sstream>
#include <iostream>
#include <iomanip>
int main() {std::ostringstream oss;oss << "Hello, " << 42 << " world!";std::string result = oss.str();std::cout << result << std::endl;std::ostringstream oss1;oss1 << std::setprecision(3) << 3.14159;//设置精度,包含在头文件iomanipstd::string result1 = oss1.str();std::cout << result1 << std::endl;return 0;
}

         istringstream:

#include <iostream>
#include <sstream>
#include <string>int main() {std::string data = "42 3.14 hello";std::istringstream iss(data);int num;double pi;std::string str;iss >> num >> pi >> str;std::cout << num << ", " << pi << ", " << str << std::endl;}

         stringstream:

        stringstream系列底层维护了⼀个string类型的对象用来保存结果,使用方法跟上面的文件流类似,只是数据读写交互的都是底层的string对象。string流使用str函数获取底层的string对象,或者写入底层的string对象,具体细节参考下面代码理解

#include <iostream>
#include <sstream>
#include <string>
#include<vector>int main() {std::stringstream ss;ss << "Hello, " << 123 << " world!";std::string result = ss.str();std::cout << result << std::endl; // 输出:Hello, 123 world!std::string input = "apple orange banana";std::stringstream ss1(input);std::string token;std::vector<std::string> tokens;while (ss1 >> token) {tokens.push_back(token);}for (const auto& t : tokens) {std::cout << t << std::endl;}std::stringstream ss2;ss2 << "First use";std::cout << ss2.str() << std::endl;ss2.clear();ss2.str("");ss2 << "Second use";std::cout << ss2.str() << std::endl;return 0;
}

        好了,今天的内容就分享到这,我们下期再见!

 

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

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

相关文章

语音识别的速度革命:从 Whisper 到 Whisper-CTranslate2,我经历了什么?

Whisper-CTranslate2&#xff1a;语音识别的速度革命 大家好&#xff0c;一个沉迷于 AI 语音技术的 “音频猎人”。最近在处理大量播客转录项目时&#xff0c;我被传统语音识别工具折磨得苦不堪言 ——RTX 3090 跑一个小时的音频要整整 20 分钟&#xff0c;服务器内存分分钟爆满…

JVM 内存模型详解:GC 是如何拯救内存世界的?

JVM 内存模型详解&#xff1a;GC 是如何拯救内存世界的&#xff1f; 引言 Java 虚拟机&#xff08;JVM&#xff09;是 Java 程序运行的基础&#xff0c;其核心特性之一就是自动内存管理。与 C/C 不同&#xff0c;Java 开发者无需手动分配和释放内存&#xff0c;而是由 JVM 自动…

分布式全局唯一ID生成:雪花算法 vs Redis Increment,怎么选?

在黑马点评项目实战中&#xff0c;关于全局唯一ID生成的实现方案选择中&#xff0c;我看到有人提到了雪花算法&#xff0c;本文就来简单了解一下雪花算法与Redis的incr方案的不同。在分布式系统开发中&#xff0c;“全局唯一ID”是绕不开的核心问题。无论是分库分表的数据库设计…

(新手友好)MySQL学习笔记(完):事务和锁

事务和锁事务transaction&#xff0c;一组原子性的SQL查询&#xff0c;或者说是一个独立的工作单元。如果能够成功执行这组查询的全部语句&#xff0c;就会执行这组查询&#xff1b;如果其中任何一条语句无法成功执行&#xff0c;那么这组查询的所有语句都不会执行。也就是说&a…

【CMake】使用 CMake 将单模块 C 项目构建为库并链接主程序

目录1. 项目结构设计&#x1f4e6; 结构说明2. 项目文件内容2.1 顶层 CMakeLists.txt2.2 模块 src/color/CMakeLists.txt ✅【推荐写法】❓是否需要写 project()&#xff1f;2.3 模块头文件 include/color.h2.4 模块实现文件 src/color/color.c2.5 主程序 src/main.c3. 构建与运…

从零开始的云计算生活——番外4,使用 Keepalived 实现 MySQL 高可用

目录 前言 一、架构原理​ ​Keepalived 作用​ ​MySQL 主从复制​ 二、环境准备​ 服务器要求​&#xff1a; 安装基础软件​ 三、配置 MySQL 主从复制 四、配置 Keepalived 主节点配置​&#xff08;/etc/keepalived/keepalived.conf&#xff09; 从节点配置 五、…

list类的常用接口实现及迭代器

目录 1. list类的介绍 2.list类的常用接口 2.1 list类的常用构造 2.2 list类对象的容量操作 2.3 list迭代器 2.4 list类的常用操作 3.list的模拟实现 1. list类的介绍 list代表的是双向链表&#xff0c;常见的有创建&#xff0c;增&#xff0c;删&#xff0c;改几个接口…

vscode Cline接入火山引擎的Deepseek R1

创建火山引擎Deepseek R1的API 在火山引擎管理控制台中创建Deepseek R1推理接入点&#xff08;大模型&#xff09;&#xff0c;创建成功后会看到下图效果。在操作中选择API调用&#xff0c;在页面中选择OpenAI SDK&#xff0c;按照步骤找到baseUrl地址和API_KEY&#xff0c;后续…

新手向:自动化图片格式转换工具

大家好&#xff01;今天我要分享一个非常实用的Python小工具——图片格式批量转换器。如果你经常需要处理大量不同格式的图片文件&#xff0c;或者需要统一图片格式以便于管理&#xff0c;那么这个工具将会成为你的得力助手&#xff01;一、为什么需要图片格式转换&#xff1f;…

CUDA中的内存管理、锁页内存、UVA统一虚拟地址、零拷贝、统一内存

文章目录0 前言1 swap内存跟锁页内存2 UVA(Unified Virtual Addressing)统一虚拟地址3 先看最普通的cuda内存分配、释放、传输4 申请锁页内存4.1 cudaHostAllocDefault4.2 cudaHostAllocPortable4.3 cudaHostAllocWriteCombined4.3 cudaHostAllocMapped4.4 几种锁页内存总结4.5…

微服务环境下的灰度发布与金丝雀发布实战经验分享

微服务环境下的灰度发布与金丝雀发布实战经验分享 在大规模微服务架构中&#xff0c;如何平滑安全地上线新功能是每个后端团队的痛点。本文将结合生产环境中的真实案例&#xff0c;分享灰度发布&#xff08;Gray Release&#xff09;与金丝雀发布&#xff08;Canary Release&am…

MEF 在 WPF 中的简单应用

MEF核心笔记MEF 的开发模式主要适用于插件化的业务场景中&#xff0c;C/S 和 B/S 中都有相应的使用场景&#xff0c;其中包括但不限于 ASP.NET MVC 、ASP WebForms、WPF、UWP 等开发框架。当然&#xff0c;DotNet Core 也是支持的。 以下是搜索到一些比较好的博文供参考&#…

Gitlab跑CICD的时候,maven镜像和pom.xml使用的maven版本冲突导致没办法build成功的解决方法

是这样的&#xff01;最近遇到一个非常棘手的难题&#xff0c;我搞了大概2周时间才把他弄出来&#xff0c;因为自己搭了个私服的maven仓库&#xff0c;他不像maven官方仓库一样&#xff0c;可以跟nginx一样转的&#xff0c;所以遇到好几个难点&#xff01;第一点&#xff1a;就…

Linux内核IPv4路由查找:LPC-Trie算法的深度实践

在互联网基础设施的核心领域,路由查找性能直接决定了网络转发效率。Linux内核作为现代网络系统的基石,其IPv4路由子系统采用了一种名为LPC-Trie(Level-Compressed Trie) 的创新数据结构,在net/ipv4/fib_trie.c文件中实现了高效的路由管理方案。本文将深入剖析这一机制的设…

【设计模式】装饰(器)模式 透明装饰模式与半透明装饰模式

装饰模式&#xff08;Decorator Pattern&#xff09;详解一、装饰模式简介 装饰模式&#xff08;Decorator Pattern&#xff09; 是一种 结构型设计模式&#xff0c;它允许你动态地给对象添加行为或职责&#xff0c;而无需修改其源代码&#xff0c;也不需要使用继承来扩展功能。…

NAT原理与实验指南:网络地址转换技术解析与实践

NAT实验 NAT&#xff08;Network Address Translation&#xff0c;网络地址转换&#xff09;&#xff1a; NAT技术的介绍&#xff1a; 随着Internet用户的快速增长&#xff0c;以及地址分配不均等因素&#xff0c;IPv4地址&#xff08;约40亿的空间地址&#xff09;已经陷入不…

设计模式之【观察者模式】

目录 观察者模式中的角色 通过一个简单案例来演示观察者模式 被观察者接口 事件类型 up主类作为被观察者 观察者接口 粉丝类作为观察者 测试 测试结果 观察者模式中的角色 被观察者(observable)观察者(observer) 通过一个简单案例来演示观察者模式 被观察者接口 /*…

Linux sudo host权限提升漏洞(CVE-2025-32462)复现与原理分析

免责声明 本文所述漏洞复现方法仅供安全研究及授权测试使用&#xff1b; 任何个人/组织须在合法合规前提下实施&#xff0c;严禁用于非法目的&#xff1b; 作者不对任何滥用行为及后果负责&#xff0c;如发现新漏洞请及时联系厂商并遵循漏洞披露规则。 漏洞简述 Linux sudo是l…

【uni-ui】hbuilderx的uniapp 配置 -小程序左滑出现删除等功能

1.网址&#xff1a;https://ext.dcloud.net.cn/plugin?id181](https://ext.dcloud.net.cn/plugin?id181) 2.csdn讲解&#xff1a;https://blog.csdn.net/qq_40323256/article/details/114337128 3.uni-ui git&#xff1a;https://github.com/dcloudio/uni-ui 4.官方网址文档&…

记一次POST请求中URL中文参数乱码问题的解决方案

POST请求中URL中文参数乱码前言&#xff1a;一个常见的开发痛点一、问题现象与原因深度解析1. 典型问题场景2. 根本原因分析URL编码规范问题&#xff1a;编码解码过程不一致&#xff1a;IE浏览器特殊行为&#xff1a;二、前端解决方案1. 手动编码URL参数&#xff08;推荐&#…