解密C++ I/O流的全新边界:高效操作与未来科技的完美融合

解密C++ I/O流的全新边界:高效操作与未来科技的完美融合

C++ IO流详解:文件读写、字符串流

在这里插入图片描述

🌏个人博客主页:个人主页

在这里插入图片描述

1. C语言的输入与输出

C语言中我们用到的最频繁的输入输出方式就是scanf ()与printf()。 scanf(): 从标准输入设备(键
盘)读取数据,并将值存放在变量中。printf(): 将指定的文字/字符串输出到标准输出设备(屏幕)。
注意宽度输出和精度输出控制。C语言借助了相应的缓冲区来进行输入与输出。如下图所示:

在这里插入图片描述

这里只需要记住两个点就可以了。

输出:把内存中的数据写到设备(文件)当中。
输入:把设备(文件)中的数据读到内存当中。

2. 流是什么

流简单来说指的是数据从一个地方流向另一个地方。

在这里插入图片描述

C++流是指信息从外部输入设备(如键盘)向计算机内部(如内存)输入和从内存向外部输出设备(显示器)输出的过程。这种输入输出的过程被形象的比喻为“流”

3. C++IO流

为了实现这种流动,C++定义了I/O标准类库,这些每个类都称为流/流类,用以完成某方面的功能

在这里插入图片描述


C++标准库提供了4个全局流对象cin、cout、cerr、clog,使用cout进行标准输出,即数据从内存流向控制台(显示器)。使用cin进行标准输入即数据通过键盘输入到程序中,同时C++标准库还提供了cerr用来进行标准错误的输出,以及clog进行日志的输出,从上图可以看出,cout、cerr、clog是ostream类的三个不同的对象,因此这三个对象现在基本没有区别,只是应用场景不同。

C++ IO 流总结

类名继承自描述实例对象
std::ios_base-所有 I/O 流类的基类,提供通用的 I/O 操作和状态管理功能-
std::iosstd::ios_base抽象类,用于处理格式化的输入输出-
std::istreamstd::ios输入流类,用于从输入源读取数据std::cin
std::ostreamstd::ios输出流类,用于向输出目标写入数据std::cout, std::cerr, std::clog
std::iostreamstd::istream, std::ostream双向流类,同时支持输入和输出-
std::fstreamstd::iostream文件流类,用于文件的输入输出-
std::ifstreamstd::istream文件输入流类,专门用于从文件读取数据-
std::ofstreamstd::ostream文件输出流类,专门用于向文件写入数据-
std::stringstreamstd::iostream字符串流类,用于在内存中构建和解析字符串-
std::istringstreamstd::istream字符串输入流类,用于从字符串读取数据-
std::ostringstreamstd::ostream字符串输出流类,用于向字符串写入数据-

实例对象说明

  • std::cin:标准输入流对象,通常连接到键盘输入。
  • std::cout:标准输出流对象,通常连接到屏幕输出。
  • std::cerr:标准错误流对象,通常也连接到屏幕输出,但不缓冲,立即显示。
  • std::clog:标准日志流对象,通常连接到屏幕输出,缓冲后显示。

istream类型对象转换为逻辑条件判断值

在线OJ中的输入和输出:

  • 对于IO类型的算法,一般都需要循环输入:
  • 输出:严格按照题目的要求进行,多一个少一个空格都不行。
  • 连续输入时,vs系列编译器下在输入ctrl+Z时结束
intmain(){ string str;//ctrl + c 信号强杀进程//ctrl + z + 换行 流对象提前提取到流结束标识//iostream& operator >> (iostream& is,string& str)//实际调用的时 while (operator>>(cin,str))while(cin >> str){ cout << str << endl;}return0;}

实际上我们看到使用while(cin>>i)去流中提取对象数据时,调用的是operator>>(cin,i),返回值是istream类型的对象,那么这里可以做逻辑条件值,源自于istream的对象又调用了operator bool,operator bool调用时如果接收流失败,或者有结束标志,则返回false。

在这里插入图片描述
我们也可以自己重载一个operator bool,当我们输入的年为0时,就结束输入。
classDate{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){}operatorbool(){if(_year ==0){returnfalse;}returntrue;}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;}intmain(){ Date d(2022,4,10); cout << d;while(d){ cin >> d; cout << d << endl;}return0;}

📢小知识:在io需求比较高的地方,如部分大量输入的竞赛题中,加上以下3行代码,可以提高C++IO效率。

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

C++文件IO流

C++根据文件内容的数据格式分为二进制文件和文本文件。

模式描述
inInput mode (输入模式)。以读取模式打开文件用于输入操作。
outOutput mode (输出模式)。以写入模式打开文件用于输出操作。如果文件已存在,内容将被截断。
appAppend mode (追加模式)。在每次写入时,数据将被追加到文件的末尾,而不是覆盖现有内容。
binaryBinary mode (二进制模式)。以二进制方式打开文件,不进行任何字符转换。这对于非文本文件(如图像或可执行文件)是必要的。
ateAt end mode (文件末尾模式)。打开文件时,文件指针定位到文件末尾。
truncTruncate mode (截断模式)。打开文件时,将文件的内容清空(如果文件已存在)。

二进制读写

二进制读写很简单,只要把内容以二进制的方式一个一个写到文件里面,在从文件里面以二进制的方式一个一个读出来就可以了。

#include<fstream>#include<string>// 定义服务器信息结构体structServerInfo{char _address[32];// 存储服务器地址,最大长度为31个字符加上一个终止符int _port;// 存储服务器端口号 Date _date;// 存储日期,假设 Date 是一个已定义的日期类};// 定义配置管理器类structConfigManager{// 构造函数,初始化文件名ConfigManager(constchar* filename):_filename(filename)// 初始化成员变量 _filename{}// 将 ServerInfo 结构体写入二进制文件voidWriteBin(const ServerInfo& info){ std::ofstream ofs(_filename, std::ofstream::out | std::ofstream::binary);// 打开文件,以二进制模式写入// std::ofstream::out 表示写入模式// std::ofstream::binary 表示二进制模式 ofs.write((char*)&info,sizeof(info));// 将整个 ServerInfo 结构体的数据写入文件// (char*)&info 将结构体指针转换为 char* 类型// sizeof(info) 获取结构体的大小}// 从二进制文件读取 ServerInfo 结构体voidReadBin(ServerInfo& info){ std::ifstream ifs(_filename, std::ifstream::in | std::ifstream::binary);// 打开文件,以二进制模式读取// std::ifstream::in 表示读取模式// std::ifstream::binary 表示二进制模式 ifs.read((char*)&info,sizeof(info));// 从文件中读取数据到 ServerInfo 结构体// (char*)&info 将结构体指针转换为 char* 类型// sizeof(info) 获取结构体的大小}private: std::string _filename;// 存储配置文件的名称};
intmain(){ ServerInfo winfo ={"192.0.0.1",80,{2024,11,18}}; ConfigManager cm("mytest.txt"); cm.WriteBin(winfo);}
在这里插入图片描述


注意:这里的 char _address[32];不能换成string _address,因为二进制读写只会把对象里面的内容全部读出来或者写进去。

如果一个进程就会出现浅拷贝的问题,因为二进制读写只会把对象里面的内容原封不动读给另一个对象,那么析构的时候就会析构两次,从而报错。

在这里插入图片描述

不同进程就会出现野指针的问题,因为之前的进程结束,栈帧空间就会销毁,string对象的_str指向的空间就是无效的内容。

在这里插入图片描述

文本读写

文本读写就是在外存上以ASCII码的形式存储,那么久需要在存储前转换成字符串,C++里面有流插入流提取就很方便。

#include<fstream>#include<string>// 定义一个结构体来存储服务器信息structServerInfo{ std::string _address;// 服务器地址int _port;// 服务器端口 std::string _date;// 日期};// ConfigManager 类用于管理配置文件的读写操作structConfigManager{// 构造函数,接受一个文件名作为参数ConfigManager(const std::string& con):_filename(con)// 初始化文件名成员变量{}// 将 ServerInfo 结构体中的信息写入文件voidWriteText(const ServerInfo& info){ std::ofstream ofs(_filename);// 打开文件,用于写入if(!ofs.is_open()){throw std::runtime_error("Failed to open file for writing.");}// 写入服务器地址 ofs << info._address << std::endl;// 写入服务器端口 ofs << info._port << std::endl;// 写入日期 ofs << info._date << std::endl;}// 从文件中读取信息到 ServerInfo 结构体中voidReadText(ServerInfo& info){ std::ifstream ifs(_filename);// 打开文件,用于读取if(!ifs.is_open()){throw std::runtime_error("Failed to open file for reading.");}// 读取服务器地址 ifs >> info._address;// 读取服务器端口 ifs >> info._port;// 读取日期 ifs >> info._date;}private: std::string _filename;// 存储配置文件的路径和名称};
intmain(){ ServerInfo winfo ={"192.0.0.1",80,{2024,11,18}}; ConfigManager cm("mytest.txt"); cm.WriteText(winfo);}
在这里插入图片描述

4. stringstream的简单介绍

在C语言中,如果想要将一个整形变量的数据转化为字符串格式,如何去做?

  1. 使用itoa()函数
  2. 使用sprintf()函数

但是两个函数在转化时,都得需要先给出保存结果的空间,那空间要给多大呢,就不太好界定,而且转化格式不匹配时,可能还会得到错误的结果甚至程序崩溃。

std::stringstream 是 C++ 标准库中的一种流类型,它可以用于字符串的输入和输出操作。它的两个常见子类分别是 std::istringstreamstd::ostringstream,它们分别用于从字符串读取数据和向字符串写入数据。

子类功能描述
std::istringstream用于从字符串中提取数据。类似于输入流(std::istream),但数据来源是字符串而不是文件或标准输入。
std::ostringstream用于向字符串写入数据。类似于输出流(std::ostream),但数据的目标是字符串而不是文件或标准输出。
// 定义一个表示聊天信息的结构体structChatInfo{ std::string _name;// 用户名int _id;// 用户ID Date _date;// 日期 std::string _msg;// 消息内容};intmain(){// 创建一个 ChatInfo 对象并初始化 ChatInfo winfo ={"张三",135246,{2024,11,6},"晚上一起看电影吧!"};// 使用 ostringstream 将 ChatInfo 对象的内容转换为字符串 std::ostringstream oss; oss << winfo._name << std::endl;// 写入用户名 oss << winfo._id << std::endl;// 写入用户ID oss << winfo._date << std::endl;// 写入日期 oss << winfo._msg << std::endl;// 写入消息内容// 获取转换后的字符串 std::string str = oss.str();// 输出字符串内容 std::cout << str << std::endl;// 创建另一个 ChatInfo 对象用于读取 ChatInfo rinfo;// 使用 istringstream 从字符串中读取 ChatInfo 对象的内容 std::istringstream iss(str); iss >> rinfo._name >> rinfo._id >> rinfo._date >> rinfo._msg;// 输出分割线 std::cout <<"-------------------------------------------------------"<< std::endl;// 输出读取到的聊天信息 std::cout <<"姓名:"<< rinfo._name <<"("<< rinfo._id <<") "; std::cout << rinfo._date << std::endl; std::cout << rinfo._name <<":>"<< rinfo._msg << std::endl;// 输出分割线 std::cout <<"-------------------------------------------------------"<< std::endl;return0;}
在这里插入图片描述

注意:

  1. stringstream实际是在其底层维护了一个string类型的对象用来保存结果。
  2. 可以使用s.str()将让stringstream返回其底层的string对象。

总结
本文全面讲解了流的基本概念,C语言和C++的输入输出方式,详细描述了流的概念、标准流、文件IO流以及字符串(stringstream)的用法

在这里插入图片描述

Read more

Java各大厂实习面试题面经新鲜出炉!---壹

Java各大厂实习面试题面经新鲜出炉!---壹

🌟 Hello,我是Java学习通! 🌈 在彩虹般绚烂的技术栈中,我是那个永不停歇的色彩收集者。 🦋 每一个优化都是我培育的花朵,每一个特性都是我放飞的蝴蝶。 🔬 每一次代码审查都是我的显微镜观察,每一次重构都是我的化学实验。 🎵 在编程的交响乐中,我既是指挥家也是演奏者。让我们一起,在技术的音乐厅里,奏响属于程序员的华美乐章。 目录 1.MySQL事务机制(阿里巴巴) 2.有做过SQL优化的实现么(阿里巴巴) 3.Nacos底层是如何实现注册中心功能的:(阿里巴巴) 4.RocketMQ如何持久化(阿里巴巴) 5.介绍一下websocket(阿里巴巴) 6.如何判断是http是长连接还是短连接,怎么设置长连接(阿里巴巴) 7.HashMap的实现原理(快手) 8.HashMap承载的元素越来越少,什么时候会退化成链表,为什么两者设置的这个值不对称(快手) 9.mysql和redis的一致性怎么保证的(快手) 10.数据库有哪些隔离级别 默认的隔离级别是什么(快手) 11.缓存击穿

By Ne0inhk
【Java 开发日记】我们来说一下 Mybatis 的缓存机制

【Java 开发日记】我们来说一下 Mybatis 的缓存机制

目录 核心概览 一级缓存 1. 作用域 2. 工作机制 3. 示例说明 4. 注意事项 二级缓存 1. 作用域 2. 开启与配置 3. 工作机制 4. 示例说明 5. 注意事项 缓存顺序与总结 使用建议 核心概览 * 一级缓存:默认开启,作用范围在 同一个 SqlSession 内。 * 二级缓存:需要手动配置开启,作用范围在 同一个 Mapper 命名空间(即同一个 Mapper 接口)内,可以被多个 SqlSession 共享。 一级缓存 1. 作用域 * SqlSession 级别:当同一个

By Ne0inhk
UnityMCP+Claude+VSCode,构建最强AI游戏开发环境

UnityMCP+Claude+VSCode,构建最强AI游戏开发环境

* 前言 * 一、UnityMCP+Claude+VSCode,构建最强AI 游戏开发环境 * 1.1 介绍 * 1.2 使用说明及下载 * 二、VSCode配置 * 2.1 连接UnityMCP * 2.2 在VSCode中添加插件 * 2.3 Claude安装 * 2.4 VSCode MCP配置 * 2.5 使用Claude开发功能 * 三、相关问题 * 总结 前言 * 本篇文章来介绍使用 UnityMCP+Claude+VSCode,打造一个更智能、高效的游戏开发工作流。 * 借助MCP工具,Claude可以直接与Unity编辑器进行双向指令交互,开发者则可以直接使用自然语言进行Unity游戏开发。 * 这一组合充分利用了AI的代码生成、问题诊断与创意辅助能力,极大提升了Unity项目的开发效率与质量。 一、UnityMCP+Claude+

By Ne0inhk

更新后的主流AI IDE/工具对比表

更新后的主流AI IDE/工具对比表 工具名称 类型 / 开发商 核心定位与特点 定价(个人) 适用场景与人群 Cursor AI原生IDE (Anysphere) 项目级上下文理解最强,支持多Agent并行协作,自研Composer模型,响应快。 $20/月 追求极致生产力、处理中大型复杂项目的全栈开发者。 Windsurf AI原生IDE (Codeium) 多文件智能体(Agent)能力突出,终端集成好,执行复杂任务流畅,被视为“Cursor平替”。 $15/月 需要深度处理大型代码库、注重重构和终端工作流的开发者。 GitHub Copilot IDE插件 (微软/GitHub) 生态最成熟,与VS Code、JetBrains等IDE无缝集成,补全准确稳定,用户基数最大。 $10/月起 大多数开发者的稳妥选择,尤其适合GitHub生态用户和团队协作。

By Ne0inhk