C++ IO流全解析:标准库中的数据处理与文件读写艺术

🌈 个人主页:Zfox_
🔥 系列专栏:C++从入门到精通

目录

  • 一: 🔥 C语言的输入与输出
  • 二: 🔥 流是什么
  • 三: 🔥 C++IO流
    • 🚀 3.1 C++标准IO流
    • 🚀 istream类型对象转换为逻辑条件判断值
    • 🚀 3.2 C++IO的性能
    • 🚀 3.3 C++文件IO流
  • 四: 🔥 stringstream的简单介绍
  • 🚀 共勉

一: 🔥 C语言的输入与输出

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

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

🎯 注意宽度输出和精度输出控制。C语言借助了相应的缓冲区来进行输入与输出。如下图所示:

💢 对输入输出缓冲区的理解:

🎯 1.可以屏蔽掉低级 I/O 的实现,低级 I/O 的实现依赖操作系统本身内核的实现,所以如果能够屏蔽这部分的差异,可以很容易写出可移植的程序。

🎯 2.可以使用这部分的内容实现“行”读取的行为,对于计算机而言是没有“行”这个概念,有了这部分,就可以定义“行”的概念,然后解析缓冲区的内容,返回一个“行”。

二: 🔥 流是什么

  • “流” 即是流动的意思,是物质从一处向另一处流动的过程,是对一种有序连续且具有方向性的数据 ( 其单位可以是bit,byte,packet ) 的抽象描述。
  • C++流 是指信息从外部输入设备(如键盘)向计算机内部(如内存)输入和从内存向外部输出设备(显示器)输出的过程。这种输入输出的过程被形象的比喻为“流”。
  • 它的特性是:有序连续、具有方向性 。

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

三: 🔥 C++IO流

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

🚀 3.1 C++标准IO流

🍐 ios_base是基类,ios 继承了 ios_base。通过 ios又分别设置了两个子类istreamostream 。这两个类分别都有一个实例对象 cincout!此外ostream还要标准错误cerr和日志输出clog。除了标准IO外,istreamostream 还有子类,文件流和string流,来提供特殊的使用!

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

再来看operator bool , 这个保证了流输入输出可以转换为bool进行一个判断。在输出输入出错时可以进行一个判断。而operator bool 会去检查四个标志值,按照对应映射返回true或false:

  1. goodbit : 表示一切正常!
  2. eofbit : 读取到结束,会设置这个比特位!
  3. failbit发生一些基本的逻辑错误,会设置这个比特位!
  4. badbit : 发生不可修复的错误,会设置这个比特位!一般不会遇到种错误!
    在这里插入图片描述
    我们来看一下这四个标志:
string str;while (cin >> str)
{cout << str << endl;
}// 原型如下  重载了 >> 和 bool  就会返回 true 或 false   通过检查failbit这个标志while (operator>>(cin, str).operator bool())
{cout << cin.good() << endl;     // 1cout << cin.eof() << endl;      // 0  cout << cin.bad() << endl;      // 0cout << cin.fail() << endl;     // 0  cout << str << endl;
}

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

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

🚀 3.2 C++IO的性能

💢 C++为了兼容C语言,会做出一些妥协优化。C语言的缓冲区只有遇到刷新标志时才会进行刷新,而如果printf缓冲区还没有刷新,我们使用cout会出现什么情况?会先把printf缓冲区刷新出来,再打印cout输出的内容,所以cout之前会先对缓冲区进行检查!所以C++风格IO需要和C风格IO进行缓冲区同步!

并且iostream库中的缓冲区通常是动态分配的,而stdio库中的缓冲区通常是静态分配的。动态分配和释放内存比静态分配内存要慢。

在上面的输出格式中我们看到iostream库支持丰富的格式化选项,C++风格IO需要再运行时进行解析处理,但是C风格IO在编译时就已经确认好输出格式了,这减少了运行时的开销。

对于有大量IO的场景,C++的IO效率会比C风格IO慢,可以使用下面三行代码来进行优化:

ios_base::sync_with_stdio(0);
cin.tie(nullptr);
cout.tie(nullptr);
  • ios_base::sync_with_stdio(0)
    🎯 这行代码的作用是取消 C++ 的 iostream 库与 C 的 stdio 库的同步。通过将 sync_with_stdio 设置为 false,可以解除这种同步,从而提高 I/O 的性能。但是,这样做之后,就不能在同一个程序中混合使用 iostream 和 stdio 函数了,因为它们不再保持同步。

  • cin.tie(nullptr)
    🎯 在默认情况下,cin 和 cout 是绑定在一起的,这意味着每次读取 cin 或写入 cout 后,都会立即刷新 cout 的缓冲区。这确保了输入输出操作的顺序性,但可能会导致性能下降。通过将 cin 的绑定解除,可以防止在每次读取输入时自动刷新输出缓冲区,从而提高性能。

  • cout.tie(nullptr)
    🎯 类似于对 cin 的操作,这行代码将 cout 的绑定解除。默认情况下,cout 与 cin 绑定,当 cin 被读取时,cout 的缓冲区会被刷新。将 cout 的.tie()设置为 nullptr,可以防止 cout 在 cin 被读取时自动刷新,从而提高性能。

🚀 3.3 C++文件IO流

🍊 C++根据文件内容的数据格式分为二进制文件文本文件。采用文件流对象操作文件的一般步骤:

  1. 定义一个文件流对象
  • ifstream (只输入用)
  • ofstream (只输出用)
  • fstream (既输入又输出用) (继承了ifstream和ofstream)
  1. 使用文件流对象的成员函数打开一个磁盘文件,使得文件流对象和磁盘文件之间建立联系 。
    open:打开文件,可以设置对应的打开方式和C语言很类似。
  2. 使用提取和插入运算符对文件进行读写操作,或使用成员函数进行读写。
  3. 关闭文件。
打开方式功能
inInput mode (输入模式)。打开文件用于输入操作
outOutput mode (输出模式)。打开文件用于输出操作
appAppend mode (追加模式)。在每次写入时,数据将被追加到文件的末尾,而不是覆盖现有内容
binaryBinary mode (二进制模式)。以二进制方式打开文件,不进行任何字符转换。这对于非文本文件(如图像或可执行文件)是必要的。
ateAt end mode (文件末尾模式)。打开文件时,文件指针定位到文件末尾。
truncTruncate mode (截断模式)。如果文件已经存在,则在打开时将其长度截断为0,即删除文件中的所有内容

🍐 写入操作可以使用<<进行流写入,也可以通过write写入一个缓冲区字符串。读取操作可以通过>>来一个一个字符读取,也可以通过read直接读取到缓冲区中。

🌰 代码示例:

struct ServerInfo
{char _address[32];int _port;Date _date;
};struct ConfigManager
{
public:ConfigManager(const char* filename):_filename(filename){}void WriteBin(const ServerInfo& info){ofstream ofs(_filename, ios_base::out | ios_base::binary);ofs.write((const char*)&info, sizeof(info));}void ReadBin(ServerInfo& info){ifstream ifs(_filename, ios_base::in | ios_base::binary);ifs.read((char*)&info, sizeof(info));}// C++文件流的优势就是可以对内置类型和自定义类型,都使用// 一样的方式,去流插入和流提取数据// 当然这里自定义类型Date需要重载>> 和 <<// istream& operator >> (istream& in, Date& d)// ostream& operator << (ostream& out, const Date& d)void WriteText(const ServerInfo& info){ofstream ofs(_filename);ofs << info._address << " " << info._port << " " << info._date;}void ReadText(ServerInfo& info){ifstream ifs(_filename);ifs >> info._address >> info._port >> info._date;}
private:string _filename; // 配置文件
};int main()
{ServerInfo winfo = { "192.0.0.1", 80, { 2022, 4, 10 } };// 二进制读写ConfigManager cf_bin("test.bin");cf_bin.WriteBin(winfo);ServerInfo rbinfo;cf_bin.ReadBin(rbinfo);cout << rbinfo._address << " " << rbinfo._port << " "<< rbinfo._date << endl;// 文本读写ConfigManager cf_text("test.text");cf_text.WriteText(winfo);ServerInfo rtinfo;cf_text.ReadText(rtinfo);cout << rtinfo._address << " " << rtinfo._port << " " <<rtinfo._date << endl;return 0;
}

四: 🔥 stringstream的简单介绍

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

  1. 使用 itoa() 函数
  2. 使用 sprintf() 函数
    但是两个函数在转化时,都得需要先给出保存结果的空间,那空间要给多大呢,就不太好界定,而且转化格式不匹配时,可能还会得到错误的结果甚至程序崩溃。
  • 在C++中,可以使用 stringstream 类对象来避开此问题。

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

🍊 stringstream 主要可以用来:

  1. 将数值类型数据格式化为字符串
#include<sstream>int main()
{int a = 12345678;string sa;// 将一个整形变量转化为字符串,存储到string类对象中stringstream s;s << a;s >> sa;// clear()// 注意多次转换时,必须使用clear将上次转换状态清空掉// stringstreams在转换结尾时(即最后一个转换后),会将其内部状态设置为badbit// 因此下一次转换是必须调用clear()将状态重置为goodbit才可以转换// 但是clear()不会将stringstreams底层字符串清空掉// s.str("");// 将stringstream底层管理string对象设置成"",// 否则多次转换时,会将结果全部累积在底层string对象中s.str("");s.clear(); // 清空s, 不清空会转化失败double d = 12.34;s << d;s >> sa;string sValue;sValue = s.str(); // str()方法:返回stringsteam中管理的string类型cout << sValue << endl;return 0;
}
  1. 字符串拼接
int main()
{stringstream sstream;// 将多个字符串放入 sstream 中sstream << "first" << " " << "string,";sstream << " second string";cout << "strResult is: " << sstream.str() << endl;// 清空 sstreamsstream.str("");sstream << "third string";cout << "After clear, strResult is: " << sstream.str() << endl;return 0;
}
  1. 序列化和反序列化结构数据
struct ChatInfo
{string _name; // 名字int _id; // idDate _date; // 时间string _msg; // 聊天信息
};int main()
{// 结构信息序列化为字符串ChatInfo winfo = { "张三", 135246, { 2022, 4, 10 }, "晚上一起看电影吧"};ostringstream oss;oss << winfo._name << " " << winfo._id << " " << winfo._date << " " << winfo._msg;string str = oss.str();cout << str << endl << endl;// 我们通过网络这个字符串发送给对象,实际开发中,信息相对更复杂,// 一般会选用Json、xml等方式进行更好的支持// 字符串解析成结构信息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;
}

注意:

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

🚀 共勉

以上就是我对 C++ IO流全解析 的理解,]觉得这篇博客对你有帮助的,可以点赞收藏关注支持一波~😉
在这里插入图片描述

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

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

相关文章

野生动物检测-目标检测数据集(包括VOC格式、YOLO格式)

野生动物检测-目标检测数据集&#xff08;包括VOC格式、YOLO格式&#xff09; 数据集&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1RHpKHAyRyl0FDD4Up3MOmQ?pwdrbjq 提取码&#xff1a;rbjq数据集信息介绍&#xff1a; 共有 1504 张图像和一一对应的标注文件 标…

QStackedWidget类的使用

本文介绍QStackedWidget类的使用。 StackedWidget控件在Qt应用程序开发过程中用的还是比较多的&#xff0c;配合按钮可以实现多个页面之间相互切换&#xff0c;方便了应用程序的开发&#xff0c;本文简要介绍QStackedWidget类实际使用过程中的常用方法&#xff0c;并给出一个简…

Python画笔案例-042 绘制空心十字架

1、绘制空心十字架 通过 python 的turtle 库绘制空心十字架&#xff0c;如下图&#xff1a; 2、实现代码 绘制空心十字架&#xff0c;以下为实现代码&#xff1a; """空心十字架.py """ import turtledef draw_pattern(length):for _ in range(…

Java 学习中使用文件、网络连接等资源时,未正确关闭资源,导致资源泄漏应该怎么办?

在Java编程中&#xff0c;处理文件、网络连接、数据库连接等资源时&#xff0c;如果没有正确关闭资源&#xff0c;就会发生资源泄漏。资源泄漏会导致系统性能下降、内存占用增加&#xff0c;甚至可能导致程序崩溃&#xff0c;特别是在高负载的系统中。 一、什么是资源泄漏&…

仕考网:哈尔滨2024下半年事业单位招考公告

招聘岗位需求计划 本次计划招聘事业单位工作人员共计588名。具体招聘单位、岗位、人数、条件等情况详见《哈尔滨市2024年下半年事业单位公开招聘工作人员岗位计划表》 年龄要求&#xff1a; 满18周岁(2006年9月18日以前出生)、35(含)周岁以下(1988年9月18日及以后出生) 博士…

基于SpringBoot+Vue的考研学习分享互助平台

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于JavaSpringBootVueMySQL的考研学习…

企业图纸加密软件哪个最好用?10款常用图纸加密软件强力推荐!

在现代企业中&#xff0c;保护图纸和设计文件的安全性至关重要。以下是十款常用且功能强大的图纸加密软件推荐&#xff0c;帮助企业更好地保护其知识产权和敏感数据。 1. 安秉网盾 安秉网盾凭借其强大的加密技术和灵活的权限管理功能&#xff0c;成为企业保护图纸安全的首选。…

JavaScript高级——函数中的this

1、this是什么&#xff1f; ① 任何函数本质上都是通过某个对象来调用的&#xff0c;如果没有直接指定就是 window 。 ② 所有函数内部都有一个变量 this 。 ③ 它的值是调用函数的当前对象。 2、如何确定 this 的值&#xff1f; ① test&#xff08;&#xff09;&#xff…

强!70.3K star ! 推荐一款功能强大、开源、可视化的性能实时监控系统:Netdata

在当今复杂多变的IT环境中&#xff0c;系统性能的实时监控与分析对于确保业务连续性、系统稳定运行以及快速故障排查至关重要。随着云计算、大数据和微服务架构的普及&#xff0c;对监控系统的要求也日益增高。 今天给大家推荐一款性能监控工具为:Netdata。 它作为一款开源、…

7.测试用例设计方法 + Bug

一、正交实验法 1.使用场景 因果关系比较庞大的情况下&#xff0c;不太适合用因果图判定表&#xff0c;在这种情况下&#xff0c;一般会采用正交实验法。 2.例子&#xff1a; 字符属性设置&#xff08;4个条件&#xff09; 字体很多 字符样式很多 …

appium server gui详细按照步骤

1.安装appium server desktop Appium安装提供两种方式:桌面版和命令行版。其中桌面版又分为 Appium GuI 和 Appium Desktop 。作为初学者&#xff0c;用桌面版&#xff0c;对初学者比较友好。 官网下载地址&#xff1a;Releases appium/appium-desktop GitHubTags appium/…

百度经纬度互转高德经纬度_在线经纬度转换工具

简介说明 在线经纬度转换工具主要功能:百度经纬度转高德经纬度,高德经纬度转百度经纬度,坐标拾取,经纬度反查高德坐标拾取器,坐标拾取,经纬度反查百度坐标拾取器,坐标拾取,经纬度反查地图数据批量收集 操作界面 使用入口> 百度经纬度互转高德经纬度_在线经纬度转换工具

如何让Google收录我的网站?

其实仅仅只是收录&#xff0c;只要在GSC提交网址&#xff0c;等个两三天&#xff0c;一般就能收录&#xff0c;但收录是否会掉&#xff0c;这篇内容收录了是否有展现&#xff0c;排名&#xff0c;就是另外一个课题了&#xff0c;如果不收录&#xff0c;除了说明你的网站有问题&…

阿里云rds数据迁移

记录一下rds数据同步操作,官方文档: 跨阿里云账号迁移RDS实例. 背景:不同阿里云账号的rds中指定数据库迁移. 操作说明: 使用阿里云数据传输服务产品,选择数据迁移.注意是从目标阿里云账号的rds中操作,按照文档操作基本上没有问题. 源阿里云账号设置如上. 需要注意的是需要从源…

计算机网络 ---- 电路交换、报文交换、分组交换

目录 零、前言 一、计算机网络发展初期面临的问题 1.1 电路交换的主要特点【电话网络采用电路交换技术】 1.1.1 电路交换的基本知识介绍 1.1.2 电路交换的优缺点 1.3 报文交换技术的特点【电报网络采用报文交换技术】 1.3.1 报文交换的基本知识介绍 1.3.2 报文交换技术…

Python 基本库用法:数学建模

文章目录 前言数据预处理——sklearn.preprocessing数据标准化数据归一化另一种数据预处理数据二值化异常值处理 numpy 相关用法跳过 nan 值的方法——nansum和nanmean展开多维数组&#xff08;变成类似list列表的形状&#xff09;重复一个数组——np.tile 分组聚集——pandas.…

VScode 的简单使用

目录 1. VScode 的使用 1.1 常用插件 1.2 常用快捷键 1. VScode 的使用 1.1 常用插件 1.2 常用快捷键 也可以“ CTRLD ”&#xff1b;使用“CTRL滚轮”即可&#xff1b; ctrl /-&#xff0c;是用来展开/收起代码的&#xff1b; 比如&#xff1a;js 的多行注释是 shiftalt…

预防式编程——避免空值

文章目录 1. 输入验证2. 使用可选类型&#xff08;Optional Types&#xff09;3. 非空断言4. 安全调用运算符5. 提供默认值6. 设计模式7. 文档说明8. 数据结构的选择9. 逻辑判断10. 构造函数和初始化11. 使用工具类12. 枚举类型13. 编码规范14. 测试15. 重构16. 教育与培训 案例…

[Python学习日记-14] Python中基础语法的补充(变量增删改的过程、垃圾回收机制、变量指向关系、身份运算和None)

[Python学习日记-14] Python中基础语法的补充 变量增删改的过程 变量的指向关系 垃圾回收机制 身份运算和None 三元运算 变量增删改的过程 一、增 现在我们假设要创建一个变量名为 name 并且我们要赋它一个值“Jove”&#xff0c;那我们很自然会想到下面的代码 name &q…

使用Python本地搭建http.server文件共享服务并实现公网环境远程访问——“cpolar内网穿透”

前言 本文主要介绍如何在Windows系统电脑上使用python这样的简单程序语言&#xff0c;在自己的电脑上搭建一个共享文件服务器&#xff0c;并通过cpolar创建的公网地址&#xff0c;打造一个可以随时随地远程访问的私人云盘。 数据共享作为和连接作为互联网的基础应用&#xff…