解密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

AI Agent 架构:基础组成模块深度解析

AI Agent 架构:基础组成模块深度解析

AI Agent 架构:基础组成模块深度解析 📝 本章学习目标:本章是入门认知部分,帮助零基础读者建立对AI Agent的初步认知。通过本章学习,你将全面掌握"AI Agent 架构:基础组成模块深度解析"这一核心主题。 一、引言:为什么这个话题如此重要 在AI Agent快速发展的今天,AI Agent 架构:基础组成模块深度解析已经成为每个开发者和研究者必须了解的核心知识。无论你是技术背景还是非技术背景,理解这一概念都将帮助你更好地把握AI时代的机遇。 1.1 背景与意义 💡 核心认知:AI Agent正在从"对话工具"进化为"执行引擎",能够主动完成任务、调用工具、与外部世界交互。这一变革正在深刻改变我们的工作和生活方式。 从2023年AutoGPT的横空出世,到如今百花齐放的Agent生态,短短一年多时间,执行式AI已经从概念走向落地。根据最新统计,

By Ne0inhk

Flutter 三方库 adb 的鸿蒙化适配指南 - 在鸿蒙系统上构建极致、全能、跨平台的 Android Debug Bridge (ADB) 调试与设备管理连接引擎

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 adb 的鸿蒙化适配指南 - 在鸿蒙系统上构建极致、全能、跨平台的 Android Debug Bridge (ADB) 调试与设备管理连接引擎 在鸿蒙(OpenHarmony)系统的开发工具链(如鸿蒙版 IDE 配套工具)、自动化测试框架(Patrol/Appium)或多端协同管理应用中,如何通过 Dart 代码直接操纵安卓设备、执行 Shell 命令或进行文件传输?adb 为开发者提供了一套工业级的、基于 Dart 的标准 ADB 协议封装方案。本文将深入实战其在跨平台设备管理中的应用。 前言 什么是 ADB Dart Wrapper?它是针对 Android Debug

By Ne0inhk
【Linux】Linux基本使用和程序部署

【Linux】Linux基本使用和程序部署

🎬 那我掉的头发算什么:个人主页 🔥 个人专栏: 《javaSE》《数据结构》《数据库》《javaEE》 ⛺️待到苦尽甘来日 文章目录 * Linux环境搭建 * 环境搭建方式 * 使用云服务器 * 使用终端软件连接到Linux * Linux常用命令 * ls * pwd * cd * touch * cat * mkdir * rm * cp * mv * tail * vim * grep * ps * netstat * 搭建java部署环境 * apt * JDK * MYSQL * 部署web项目到Linux * 什么是部署 * 环境配置 * 构建项目并打包 * 上传jar包运行程序 * 杀死进程 Linux环境搭建 环境搭建方式 主要有四种: 1. 直接安装在物理机上。但是 Linux 桌面使用起来非常不友好。所以不建议。【不推荐】。 2. 使用虚拟机软件,

By Ne0inhk
Flutter 三方库 coverage_reporter 的鸿蒙化适配指南 - 实现具备 LCOV 自动分析与多格式统计的代码覆盖率报告引擎、支持端侧质量量化与 CI 流水线对齐实战

Flutter 三方库 coverage_reporter 的鸿蒙化适配指南 - 实现具备 LCOV 自动分析与多格式统计的代码覆盖率报告引擎、支持端侧质量量化与 CI 流水线对齐实战

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 coverage_reporter 的鸿蒙化适配指南 - 实现具备 LCOV 自动分析与多格式统计的代码覆盖率报告引擎、支持端侧质量量化与 CI 流水线对齐实战 前言 在进行 Flutter for OpenHarmony 的企业级应用交付时,如何客观地衡量测试用例的完备性?“代码覆盖率(Code Coverage)”是唯一的硬指标。虽然 Dart SDK 可以导出原始的 coverage 数据,但如何将其转化为直观、可读且能集成到工作流中的美观报告?coverage_reporter 是一款专为 Dart 项目设计的覆盖率报告聚合工具。本文将介绍如何在鸿蒙端构建极致、透明的质量度量底线。 一、原直观解析 / 概念介绍 1.1 基础原理 该库建立在“

By Ne0inhk