【C++高阶】深入理解C++ I/O流:标准库中的隐藏宝石

📝个人主页🌹:Eternity._
⏩收录专栏⏪:C++ “ 登神长阶 ”
🤡往期回顾🤡:C++ 特殊类
🌹🌹期待您的关注 🌹🌹

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

❀ C++ IO流

  • 📒1. C语言的输入与输出
  • 📚2. 流是什么
  • 📜3. C++ IO流
    • 🌞C++标准IO流
    • ⭐C++文件IO流
  • 📝4. stringstream
    • 🍁将数值类型数据格式化为字符串
    • 🍂字符串拼接
    • 🌸序列化和反序列化
  • 📖5. 总结


前言:在编程的世界中,输入与输出(I/O)是连接程序与现实世界的桥梁。无论是从键盘接收用户指令,还是将处理结果输出到屏幕或文件,I/O操作都是程序设计中不可或缺的一部分。对于C++这一强大而灵活的编程语言而言,其丰富的I/O流库更是为开发者提供了高效、灵活且易于使用的数据交换机制

C++的I/O流库不仅涵盖了基本的输入输出操作,如标准输入输出流(cin和cout)、文件流(ifstream和ofstream)以及字符串流(istringstream、ostringstream和stringstream),还提供了丰富的格式化选项和错误处理机制,使得开发者能够轻松应对各种复杂的I/O需求

然而,尽管C++ I/O流库功能强大,但其使用方式却相对复杂,尤其是对于初学者而言,往往难以快速掌握。因此,本文旨在通过深入浅出的方式,引导读者逐步了解C++ I/O流库的基本原理、使用方法以及高级特性。我们将从最基本的输入输出操作讲起,逐步深入到文件处理、字符串流操作、格式化输出等高级话题,帮助读者建立起对C++ I/O流库的全面认识

让我们一起走进C++ I/O流的世界,探索其背后的奥秘,共同提升编程技能,创造出更加高效、优雅的C++程序!


📒1. C语言的输入与输出

C语言中我们用到的最频繁的输入输出方式就是scanf ()与printf()

scanf(): 从标准输入设备(键盘)读取数据,并将值存放在变量中
printf(): 将指定的文字/字符串输出到标准输出设备(屏幕)

注意宽度输出和精度输出控制

C语言借助了相应的缓冲区来进行输入与输出,如图:
在这里插入图片描述

输入输出缓冲区:

  • 可以屏蔽掉低级I/O的实现,低级I/O的实现依赖操作系统本身内核的实现,所以如果能够屏
    蔽这部分的差异,可以很容易写出可移植的程序
  • 可以使用这部分的内容实现“行”读取的行为,对于计算机而言是没有“行”这个概念,有了这
    部分,就可以定义“行”的概念,然后解析缓冲区的内容,返回一个“行”

注意事项:

  • 在使用scanf()时,务必检查其返回值以确保成功读取了预期数量的输入项
  • 格式化字符串中的格式说明符应与输入数据的类型严格匹配

📚2. 流是什么

“流”即是流动的意思,是物质从一处向另一处流动的过程,是对一种有序连续且具有方向性的数据( 其单位可以是bit,byte,packet )的抽象描述

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

C++中的流(Streams)是一种抽象的概念,用于表示数据序列的源或目标。它们提供了一种统一的方法来执行输入/输出操作,无论是从文件、内存缓冲区、控制台或其他输入输出设备读取或写入数据。流的概念使得C++的输入输出操作变得既灵活又强大

流的特征:有序连续、具有方向性

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

📜3. C++ IO流

C++系统实现了一个庞大的类库,其中ios为基类,其他类都是直接或间接派生自ios类

在这里插入图片描述


🌞C++标准IO流

C++标准IO流(Standard Input/Output Streams)是C++标准库中的一部分,它们提供了一套丰富的类和函数,用于处理标准输入输出操作,如从控制台读取数据或向控制台输出数据。这些流是面向对象的,并且基于继承体系,使得它们能够灵活地处理各种输入输出任务

  • std::fstream:同时继承自std::istream和std::ostream,因此支持同时读写文件

C++标准库提供了4个全局流对象cin、cout、cerr、clog

  • 使用cout进行标准输出,即数据从内存流向控制台(显示器)
  • 使用cin进行标准输入即数据通过键盘输入到程序中
  • 同时C++标准库还提供了cerr用来进行标准错误的输出,以及clog进行日志的输出

在使用时候必须要包含文件并引入std标准命名空间

注意事项:

  • cin为缓冲流。键盘输入的数据保存在缓冲区中,当要提取时,是从缓冲区中拿。如果一次输入过多,会留在那儿慢慢用,如果输入错了,必须在回车之前修改,如果回车键按下就无法挽回了。只有把输入缓冲区中的数据取完后,才要求输入新的数据
  • 输入的数据类型必须与要提取的数据类型一致,否则出错。出错只是在流的状态字state中对
    应位置位(置1),程序继续
  • 空格和回车都可以作为数据之间的分格符,所以多个数据可以在一行输入,也可以分行输
    入。但如果是字符型和字符串,则空格(ASCII码为32)无法用cin输入,字符串中也不能有
    空格
    。回车符也无法读入
  • cin和cout可以直接输入和输出内置类型数据,原因:标准库已经将所有内置类型的输入和输出全部重载了 cin文档 cout文档
  • 对于自定义类型,如果要支持cin和cout的标准输入输出,需要对<<和>>进行重载

调用的是operator>>,返回值是istream类型的对象,那么这里可以做逻辑条件值,源自于istream的对象又调用了operator booloperator bool调用时如果接收流失败,或者有结束标志,则返回false

在这里插入图片描述
代码示例 (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){}operator bool(){// 假设输入_year为0,则结束if (_year == 0)return false;elsereturn true;}
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;
}// C++ IO流,使用面向对象+运算符重载的方式
// 能更好的兼容自定义类型,流插入和流提取
int main()
{// 自动识别类型的本质--函数重载// 内置类型可以直接使用--因为库里面ostream类型已经实现了int i = 520;double j = 13.14;cout << i << endl;cout << j << endl;// 自定义类型则需要我们自己重载<< 和 >>Date d(2024, 9, 11);cout << d;while (d){cin >> d;cout << d;}return 0;
}

⭐C++文件IO流

C++文件IO流(File Input/Output Streams)是C++标准库中的一部分,用于处理文件的读写操作。这些流封装了文件作为数据的来源或目标,使得文件的读写变得既方便又灵活。C++通过< fstream >头文件提供了文件IO流的相关类和函数

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

主要类

  • std::ifstream:继承自std::istream,用于从文件读取数据
  • std::ofstream:继承自std::ostream,用于向文件写入数据
  • std::fstream:同时继承自std::istream和std::ostream,因此支持同时读写文件

采用文件流对象操作文件的一般步骤:

    1. 定义一个文件流对象
    1. 使用文件流对象的成员函数打开一个磁盘文件,使得文件流对象和磁盘文件之间建立联系
    1. 使用提取和插入运算符对文件进行读写操作,或使用成员函数进行读写
    1. 关闭文件

二进制读写代码示例 (C++):

// 文件流对象
struct ServerInfo
{// 二进制读写时,尽量避免使用容器string _address;//char _address[32];int _port;Date _date;
};// 二进制读写
class BinIO
{
public:BinIO(const char* filename = "info.bin"):_filename(filename){}void Write(const ServerInfo& winfo){ofstream ofs(_filename, ofstream::out | ofstream::binary);ofs.write((const char*)&winfo, sizeof(winfo));}void Read(ServerInfo& rinfo){ifstream ifs(_filename, ifstream::in | ifstream::binary);ifs.read((char*)&rinfo, sizeof(rinfo));}private:string _filename = "info.bin"; // 配置文件
};int main()
{ServerInfo winfo = { "10.0.2.15", 22, {2024, 9, 12 } };BinIO bin;bin.Write(winfo);ServerInfo info;bin.Read(info);cout << info._address << endl;cout << info._port << endl;cout << info._date << endl;return 0;
}

注意:二进制读写时,尽量避免使用容器,容器中存放的指针可能会在读取文件时,释放变成野指针


文件读写代码示例 (C++):

// 文件流对象
struct ServerInfo
{string _address;//char _address[32];int _port;Date _date;
};// 文件读写
class TestIO
{
public:TestIO(const char* filename = "info.txt"):_filename(filename){}void Write(const ServerInfo& winfo){ofstream ofs(_filename);ofs << winfo._address << endl;ofs << winfo._port << endl;;ofs << winfo._date << endl;;}void Read(ServerInfo& rinfo){ifstream ifs(_filename);ifs >> rinfo._address;ifs >> rinfo._port;ifs >> rinfo._date;}private:string _filename = "info.txt"; // 配置文件
};int main()
{ServerInfo winfo = { "10.0.2.15", 22, {2024, 9, 12 } };TestIO test;test.Write(winfo);ServerInfo info;test.Read(info);cout << info._address << endl;cout << info._port << endl;cout << info._date << endl;return 0;
}

📝4. stringstream

stringstream 是 C++ 标准库中的一个非常有用的类,它属于 < sstream > 头文件。stringstream 是一种输入/输出流(I/O stream),用于在内存中执行字符串的输入输出操作,类似于 cin 和 cout,但是它是针对字符串的。stringstream 可以被用来进行字符串的格式化、解析和转换,而不需要通过文件或控制台

在程序中如果想要使用stringstream,必须要包含头文件。在该头文件下,标准库三个类:
istringstream、ostringstream 和 stringstream,分别用来进行流的输入、输出和输入输出操作


🍁将数值类型数据格式化为字符串

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

  • 使用itoa()函数 (C++中为 _itoa())
  • 使用sprintf()函数

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

代码示例 (C++):

int main()
{int n = 123456789;char s1[32];_itoa(n, s1, 10);char s2[32];sprintf(s2, "%d", n);char s3[32];sprintf(s3, "%f", n);return 0;
}

在C++中,可以使用stringstream类对象来避开此问题

代码示例 (C++):

#include<sstream>
int main()
{int a = 12345678;string sa;// 将一个整形变量转化为字符串,存储到string类对象中stringstream s;s << a;s >> sa;cout << sa << endl;s.str("");s.clear(); // 清空s, 不清空会转化失败double d = 13.14;s << d;s >> sa;string sValue;sValue = s.str(); // str()方法:返回stringsteam中管理的string类型cout << sValue << endl;return 0;
}

注意:

  • 多次转换时,必须使用clear将上次转换状态清空掉
    stringstream s在转换结尾时(即最后一个转换后),会将其内部状态设置为badbit,因此下一次转换是必须调用clear()将状态重置为goodbit才可以转换,但是clear()不会将stringstreams底层字符串清空掉
  • s.str(""),将stringstream底层管理string对象设置成"",否则多次转换时,会将结果全部累积在底层string对象中

🍂字符串拼接

关于字符串拼接,我们之前也了解过,两种常见方式:

  • std::string类中的append()函数
  • +=操作符

代码示例 (C++):

int main()
{string s1;s1 += "hello";s1 += " ";s1 += "world";cout << s1 << endl;string s2;s2.append("hello");s2.append(" ");s2.append("world");cout << s2 << endl;return 0;
}

现在我们也可以使用stringstreamostringstream来完成这一操作

代码示例 (C++):

#include<sstream>
int main()
{// stringstreamstringstream sstream;// 将多个字符串放入 sstream 中sstream << "hello" << " " << "world";cout << sstream.str() << endl;// 清空 sstreamsstream.str("");// ostringstreamostringstream oss;oss << "hello" << " " << "world";cout << oss.str() << endl;return 0;
}

🌸序列化和反序列化

序列化和反序列化是计算机科学中常用的两个概念,它们主要涉及到将数据结构或对象状态转换为可以存储或传输的格式(序列化),以及将这些格式恢复回原始的数据结构或对象状态(反序列化)。这两个过程在数据持久化、网络通信、对象深拷贝等场景中非常有用

我们通过网络这个字符串发送给对象,实际开发中,信息相对更复杂,一般会选用Json、xml等方式进行更好的支持

代码示例 (C++):

#include<sstream>struct ChatInfo
{string _name; // 名字int _id; // idDate _date; // 时间string _msg; // 聊天信息
};
int main()
{// 结构信息序列化为字符串ChatInfo winfo = { "张宝龙", 1314520, { 2024, 9, 12 }, "晚上一起激战CS:GO"};ostringstream oss;oss << winfo._name << endl;oss << winfo._id << endl;oss << winfo._date << endl;oss << winfo._msg << endl;string str = oss.str();cout << str << endl << endl;// 网络输出// 字符串解析成结构信息ChatInfo rInfo;istringstream iss(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;
}

注意事项:

  • stringstream实际是在其底层维护了一个string类型的对象用来保存结果
  • 多次数据类型转化时,一定要用clear()来清空,才能正确转化,但clear()不会将stringstream底层的string对象清空
  • 可以使用s. str("")方法将底层string对象设置为""空字符串
  • 可以使用s.str()将让stringstream返回其底层的string对象
  • stringstream使用string类对象代替字符数组,可以避免缓冲区溢出的危险,而且其会对参数类型进行推演,不需要格式化控制,也不会出现格式化失败的风险,因此使用更方便,更安全

📖5. 总结

通过本次对C++ I/O流的学习之旅,我们一同探索了C++语言中这一强大而灵活的输入输出机制。从最初的标准输入输出流cin和cout,到文件流ifstream和ofstream的深入应用,再到字符串流istringstream、ostringstream和stringstream的灵活操作,我们见证了C++ I/O流库在数据处理和交换中的无限可能

学习过程中,我们不仅掌握了C++ I/O流库的基本用法,还学会了如何利用格式化选项来定制输出格式,使数据呈现更加符合需求的形式。同时,我们也深入了解了I/O操作中可能出现的异常和错误,并学习了相应的处理策略,以确保程序的健壮性和稳定性

最后,我希望这篇文章能够成为你学习C++ I/O流过程中的一盏明灯,为你指引方向,提供帮助。在未来的编程道路上,愿你能够运用所学,创造出更加精彩、高效的C++程序。再次感谢你的阅读,期待与你在更广阔的编程世界中相遇!

在这里插入图片描述

希望本文能够为你提供有益的参考和启示,让我们一起在编程的道路上不断前行!
谢谢大家支持本篇到这里就结束了,祝大家天天开心!

在这里插入图片描述

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

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

相关文章

Stable Diffusion 优秀博客转载

初版论文地址&#xff1a;https://arxiv.org/pdf/2112.10752 主要流程图&#xff1a; Latent Diffusion Models&#xff08;LDMs&#xff09; DDPM是"Denoising Diffusion Probabilistic Models"的缩写&#xff0c; 去噪扩散概率模型 博客&#xff1a; 【论文阅读…

单发超快光场成像技术研究进展

摘要&#xff1a;单发超快光场成像技术能够在更广泛的条件下表征瞬态事件&#xff0c;为探索不可重复和难以再现的超快现象打开了大门&#xff0c;是探索未知领域必不可少的工具&#xff0c;具有巨大的科学技术应用价值。介绍近年来单发超快光场成像技术的研究进展&#xff0c;…

【Finetune】(三)、transformers之P-Tuning微调

文章目录 0、P-Tuning基本原理1、代码实战1.1、导包1.2、加载数据集1.3、数据集预处理1.4、创建模型1.5、P-tuning*1.5.1、配置文件1.5.2、创建模型 1.6、配置训练参数1.7、创建训练器1.8、模型训练1.9、模型推理 0、P-Tuning基本原理 P-Tuning的基本思想是在prompt-tuning的基…

预付费计量系统实体模型

1. 预付费计量系统实体模型 A generic entity model for electricity payment metering systems is shown in Figure 2. Although it provides a limited perspective, it does serve to convey certain essential concepts. 关于电子式预付费电表系统的实体模型见图 2…

如何选购笔记本电脑?要看哪些参数?

如何选购笔记本电脑&#xff1f;要看哪些参数&#xff1f; 文章目录 如何选购笔记本电脑&#xff1f;要看哪些参数&#xff1f;1、CPU&#xff08;中央处理器&#xff09;2、GPU&#xff08;显卡&#xff09;3、RAM&#xff08;内存&#xff09;4、硬盘5、屏幕6、散热7、接口8、…

前端工程化4:从0到1构建完整的前端监控平台

前言 一套完整的前端监控系统的主要部分&#xff1a; 数据上报方式数据上送时机性能数据采集错误数据采集用户行为采集定制化指标监控sdk 监控的目的&#xff1a; 一、数据上报方式 本文的方案是&#xff0c;优先navigator.sendBeacon&#xff0c;降级使用1x1像素gif图片…

Java | Leetcode Java题解之第417题太平洋大西洋水流问题

题目&#xff1a; 题解&#xff1a; class Solution {static int[][] dirs {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};int[][] heights;int m, n;public List<List<Integer>> pacificAtlantic(int[][] heights) {this.heights heights;this.m heights.length;this.n…

[数据结构与算法·C++] 笔记 2.1 线性表

线性结构 概念 二元组 B ( K , R ) B(K,R) B(K,R) K a 0 , a 1 , . . . , a n − 1 K{a_0,a_1,...,a_{n-1}} Ka0​,a1​,...,an−1​ ( R r R{r} Rr) 有一个唯一的开始结点&#xff0c;它没有前驱&#xff0c;有一个唯一的直接后继一个唯一的终止结点&#xff0c;它有一个…

了解你的GPU:深入探讨AMD SMI

Getting to Know Your GPU: A Deep Dive into AMD SMI — ROCm Blogs 2024年9月17日 作者&#xff1a;Matt Elliott 对于使用AMD硬件的系统管理员和高级用户来说&#xff0c;性能优化和高效的资源监控至关重要。AMD系统管理界面命令行工具amd-smi正是为了解决这些需求而设计的。…

uni-app功能 1. 实现点击置顶,滚动吸顶2.swiper一个轮播显示一个半内容且实现无缝滚动3.穿透修改uni-ui的样式

uni-app项目中遇到的功能 文章目录 uni-app项目中遇到的功能一、实现点击置顶&#xff0c;滚动吸顶、1.1、scroll-view设置不生效的原因和解决办法1.2 功能代码 二、swiper一个轮播显示一个半内容且实现无缝滚动三、穿透修改uni-ui的样式 一、实现点击置顶&#xff0c;滚动吸顶…

基于STM32残疾人辅助行走系统

要么是家人陪伴&#xff0c;要么是类似导盲犬的动物辅助&#xff0c;家人还有事要做&#xff0c;不一定实时在场&#xff0c;而动物辅助也可能会出现新的问题&#xff0c;威胁残疾人身体安全。因此利用现代计算机技术、传感器检测设备和物联网技术设计这一款辅助残疾人行走的智…

【FPGA】FPGA芯片结构

目录 1 可编程输出/输出单元&#xff08;IOB&#xff09;2 可配置逻辑块&#xff08;CLB&#xff09;3 数字时钟管理模块&#xff08;DCM&#xff09;4 嵌入式块存储器&#xff08;BRAM&#xff09;5 布线资源6 内嵌功能模块&#xff08;专用IP单元&#xff09;6.1 PLL&#xf…

MISC - 第一天(stegsolve图片隐写解析器、QR research、binwalk,dd文件分离,十六进制文件编辑器)

前言 各位师傅大家好&#xff0c;我是qmx_07&#xff0c;最近更新Buuctf在线测评中的MISC杂项内容 介绍 BUUCTF:https://buuoj.cn/ &#xff0c;整合了各大 CTF 赛事题目&#xff0c;类型丰富&#xff0c;涵盖了Web 安全、密码学、系统安全、逆向工程、代码审计等多个领域 …

C#/.NET/.NET Core技术前沿周刊 | 第 6 期(2024年9.16-9.22)

前言 C#/.NET/.NET Core技术前沿周刊&#xff0c;你的每周技术指南针&#xff01;记录、追踪C#/.NET/.NET Core领域、生态的每周最新、最实用、最有价值的技术文章、社区动态、优质项目和学习资源等。让你时刻站在技术前沿&#xff0c;助力技术成长与视野拓宽。 欢迎投稿&…

数据库 MySQL 是否需要容器化?

容器的定义&#xff1a;容器是为了解决“在切换运行环境时&#xff0c;如何保证软件能够正常运行”这一问题。 目前&#xff0c;容器和 Docker 依旧是技术领域最热门的词语&#xff0c;无状态的服务容器化已经是大势所趋&#xff0c;同时也带来了一个热点问题被大家所争论不以…

2024PHP彩虹工具网源码一个多功能工具箱程序支持72种常用站长和开发等工具

安装&#xff1a; PHP>7.4 伪静态设置Thinkphp 设置/public为网站运行目录 访问你的域名/install进行安装即可 安装扩展 sg11 &#xff0c;fileinfo &#xff0c; ionCube 常用功能 站长工具&#xff1a;ICP备案查询、IP地址查询、域名Whios查询、腾讯域名拦截查询、Mysql…

基于yolov5的中国交通标志TT100K检测系统python源码+onnx模型+评估指标曲线+精美GUI界面

【算法介绍】 基于YOLOv5的中国交通标志TT100K检测系统是一种利用深度学习技术实现高效、准确交通标志识别的系统。该系统采用YOLOv5作为核心检测算法&#xff0c;凭借其速度快、准确性高的特点&#xff0c;在实时交通标志识别领域展现出显著优势。 TT100K数据集作为该系统的…

调用本地大模型服务出现PermissionDeniedError的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

ICM20948 DMP代码详解(38)

接前一篇文章&#xff1a;ICM20948 DMP代码详解&#xff08;37&#xff09; 上一回继续解析inv_icm20948_set_slave_compass_id函数&#xff0c;解析了第3段代码&#xff0c;本回解析接下来的代码。为了便于理解和回顾&#xff0c;再次贴出该函数源码&#xff0c;在EMD-Core\so…

PMP--二模--解题--71-80

文章目录 13.干系人管理--干系人登记册--记录干系人的身份信息、评估信息、干系人分类。识别完干系人更新干系人登记册。71、 [单选] 一名初级项目经理被指派到一个新启动的项目&#xff0c;高级项目经理指示该初级项目经理去识别在项目中享有既得利益的人员。高级项目经理让初…