【C++】IO流

IO流

  • 一、C语言的输入输出
  • 二、流的概念
  • 三、C++ IO流
    • 1. C++标准IO流
    • 2. C++文件IO流
  • 四、stringstream 的简单介绍
    • 1. 将数值类型数据格式化为字符串
    • 2. 字符串拼接
    • 3. 序列化和反序列化结构数据

一、C语言的输入输出

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

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

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

在这里插入图片描述

二、流的概念

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

C++ 流是指信息从外部输入设备(如键盘)向计算机内部(如内存)输入和从内存向外部输出设备(显示器)输出的过程。这种输入输出的过程被形象的比喻为“流”。它的特性是:有序连续、具有方向性。为了实现这种流动,C++ 定义了 I/O 标准类库,这些每个类都称为流/流类,用以完成某方面的功能。

三、C++ IO流

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

在这里插入图片描述

1. C++标准IO流

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

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

注意:

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

  • 输出:严格按照题目的要求进行,多一个少一个空格都不行;

  • 连续输入时,vs 系列编译器下在输入 ctrl+Z 时结束

      				// 单个元素循环输入while (cin >> a){// ...}// 多个元素循环输入while (c >> a >> b >> c){// ...}// 整行接收while (cin >> str){// ...}
    
  1. istream 类型对象转换为逻辑条件判断值

例如文档:istream 流提取重载 和 operator bool() 重载

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

例如下面的日期类,当我们输入 _year 为 0 时,结束循环:

				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;}int main(){Date d;while (d){cin >> d;cout << d << endl;}return 0;}

2. C++文件IO流

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

  1. 定义一个文件流对象:
  • ifstream ifile(只输入用)
  • ofstream ofile(只输出用)
  • fstream iofile(既输入又输出用)
  1. 使用文件流对象的成员函数打开一个磁盘文件,使得文件流对象和磁盘文件之间建立联系;
  2. 使用提取和插入运算符对文件进行读写操作,或使用成员函数进行读写;
  3. 关闭文件;

例如我们定义一个结构体:

				struct ServerInfo{char _address[32];int _port;Date _date;};

假设我们需要向文件中写入和读取这个结构体的信息,分别用二进制读写和文本读写的方式实现;首先我们先定义一个类,将二进制读写和文本读写进行封装:

				class ConfigManager{public:ConfigManager(const char* filename = "test.txt"):_filename(filename){}void WriteBin(const ServerInfo& info){// 二进制覆盖写ofstream ofs(_filename, ofstream::out | ofstream::binary);ofs.write((const char*)&info, sizeof(info));}void ReadBin(ServerInfo& info){// 二进制读取ifstream ifs(_filename, ofstream::in | ofstream::binary);ifs.read((char*)&info, sizeof(info));}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; // 配置文件};

其中,在定义 ofstream 对象和 ifstream 对象的时候,可以以构造函数的形式传参去打开文件,也可以使用 open 接口,这里我们使用第一种方法,其构造函数的重载形式和参数解析参考文档:ofstream. 接下来我们进行测试:

				int main(){ServerInfo winfo = { "192.0.0.1", 100, { 2024, 1, 20 } };// 二进制写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.txt");cf_text.WriteText(winfo);// 文本读取ServerInfo rtinfo;cf_text.ReadText(rtinfo);// 打印读取结果cout << rtinfo._address << " " << rtinfo._port << " " << rtinfo._date << endl;return 0;}

运行结果如下:

在这里插入图片描述

我们也可以在当前目录下看见新建的两个文件:

在这里插入图片描述

注意,以二进制方式写数据的时候,不能使用二进制方式写容器,例如我们将上述的结构的信息中的 char _address[32] 改成 string

				struct ServerInfo{//char _address[32];string _address;int _port;Date _date;};

因为 string 底层是有一个指针指向的是当前字符串的空间,当我们打开一个文件:

  • 如果在同一个进程中,WriteBin 写入的时候向文件中写入的是 string 中的 _str 指针、_size_capacity,而 ReadBin 读取出来的时候是原封不动地将文件中的内容读取到另外一个对象中,也就是浅拷贝问题,相当于两个结构体对象中的 string 都指向同一个空间,所以会出现析构两次的情况。
  • 如果不同一个进程中,WriteBin 写入完成的时候并没有读取,而是进程退出,空间释放,_str 指向的空间被释放;而在另外一个进程中读取的时候,ReadBin 在读取的时候,读取的是 _str 释放掉的空间,也就是野指针问题。

四、stringstream 的简单介绍

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

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

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

				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 类对象来避开此问题。在程序中如果想要使用 stringstream,必须要包含头文件。在该头文件下,标准库三个类:istringstreamostringstreamstringstream,分别用来进行流的输入输出输入输出操作,我们这里主要介绍 stringstream.

stringstream 主要可以用来:

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

例如我们将一个整型转化为字符串,存储到 string 类对象中;代码如下:

				int main(){int a = 12345678;string sa;stringstream s;s << a;s >> sa;cout << sa << endl;return 0;}

打印结果如下:

在这里插入图片描述

注意多次转换时,必须使用 clear() 将上次转换状态清空掉,因为stringstreams 在转换结尾时(即最后一个转换后),会将其内部状态设置为 badbit,因此下一次转换是必须调用 clear() 将状态重置为 goodbit 才可以转换,但是 clear() 不会将 stringstreams 底层字符串清空掉。

同时,需要使用 s.str("")stringstream 底层管理 string 对象设置成 "" ,否则多次转换时,会将结果全部累积在底层 string 对象中。

例如我们经过上次转换后,继续转换一个 double 类型:

				int main(){int a = 12345678;string sa;stringstream s;s << a;s >> sa;s.str("");s.clear();     // 清空s, 不清空会转化失败double d = 12.34;s << d;s >> sa;cout << sa << endl;string sValue;// str()方法:返回 stringsteam 中管理的 string 类型sValue = s.str();  cout << sValue << endl;return 0;}

其中,s.str() 会返回 stringsteam 中管理的 string 类型;运行结果如下:

在这里插入图片描述

2. 字符串拼接

代码如下:

				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;}

在这里插入图片描述

3. 序列化和反序列化结构数据

示例代码如下:

				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 类对象代替字符数组,可以避免缓冲区溢出的危险,而且其会对参数类型进行推演,不需要格式化控制,也不会出现格式化失败的风险,因此使用更方便,更安全。

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

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

相关文章

HarmonyOS 应用开发入门

HarmonyOS 应用开发入门 前言 DevEco Studio Release版本为&#xff1a;DevEco Studio 3.1.1。 Compile SDK Release版本为&#xff1a;3.1.0&#xff08;API 9&#xff09;。 构建方式为 HVigor&#xff0c;而非 Gradle。 最新版本已不再支持 &#xff08;”Java、JavaScrip…

计算机基础之微处理器简介

微处理器 微处理器定义 微型计算机的CPU也被称为微处理器&#xff0c;是将运算器、控制器和高速缓存集成在一起的超大规模集成电路芯片&#xff0c;是计算机的核心部件。能完成取指令、执行指令&#xff0c;以及与外界存储器和逻辑部件交换信息等操作。 微处理器发展 CPU从…

Spring Security快速入门

入门案例 创建一个Spring MVC应用程序&#xff0c;该应用程序使用用户登录来保护页面。 Spring Initializer创建项目 如果Spring Web和Thymeleaf依赖无法下载&#xff0c;可以检查项目的Maven配置是否正确&#xff01; 创建“不安全”的Web应用程序 Web应用程序包括两个简单…

语义分割常用评价指标

在图像处理领域中&#xff0c;语义分割是很重要的一个任务。在实际项目开发中,评估模型预测效果以及各指标的含义对于优化模型极为重要。 本文将主要评价指标的计算算法进行了详细说明,并加上注释解释每个指标的含义。这对理解各指标背后的数学原理以及能否在实践中应用或许有…

UE5 C++ 学习笔记 UBT UHT 和 一些头文件

总结一些似懂非懂的知识点&#xff0c;从头慢慢梳理。 任何一个项目都有创建这些三个.cs。 这个是蓝图转C 这个是本身就是C项目,应该就是多了一个GameModeBase类 Build.cs包含了每个模块的信息&#xff0c;表明了这个项目用到了哪一些模块。该文件里的using UnrealBuilTool 是…

Linux系统Shell脚本 ----- 编程规范和变量详细解读

一、Shell脚本概述 1、什么是Shell Linux系统中运行的一种特殊程序在用户和内核之间充当“翻译官”用户登录Linux系统时&#xff0c;自动加载一个Shell程序Bash是Linux系统中默认使用的Shell程序 2、Shell的作用 Linux系统中的shell是一个特殊的应用程序&#xff0c;它介于操…

在全志H616核桃派上实现USB摄像头的OpenCV颜色检测

在给核桃派开发板用OpenCV读取图像并显示到pyqt5的窗口上并加入颜色检测功能&#xff0c;尝试将图像中所有蓝色的东西都用一个框标记出来。 颜色检测核心api 按照惯例&#xff0c;先要介绍一下opencv中常用的hsv像素格式。颜色还是那个颜色&#xff0c;只是描述颜色用的参数变…

反序列化字符串逃逸(上篇)

首先&#xff0c;必须先明白&#xff0c;这个点并不难&#xff0c;我给大家梳理一遍就会明白。 反序列化字符串逃逸就是序列化过程中逃逸出来字符&#xff0c;是不是很简单&#xff0c;哈哈哈&#xff01; 好了&#xff0c;不闹了&#xff0c;其实&#xff1a; 这里你们只要懂…

【服务器NextChat】创建部署NextChat网站

目录 🌺【前言】 🌼1. 购买服务器 🌼2.【NextChat—gpt-3.5-turbo模型】 🌻2.1 服务器设置 🌻2.2 打开Xshell软件:安装docker环境 (1)安装OpenAI (2)检查下是否运行成功 🌻2.3 重置OpenAPI 秘钥方法 🌻2.4 如需域名访问,请接着往下看 🌼3.【Ne…

Docker项目部署()

1.创建文件夹tools mkdir tools 配置阿里云 Docker Yum 源 : yum install - y yum - utils device - mapper - persistent - data lvm2 yum - config - manager -- add - repo http://mirrors.aliyun.com/docker- ce/linux/centos/docker - ce.repo 更新 yum 缓存 yum makec…

产品经理学习-产品运营《用户运营策略》

⽤户画像与⽤户运营策略 什么是用户画像 对产品运营而言&#xff0c;用户画像就是对用户的各种特征贴上标签通过这些标签将用户分成不同的用户群体 为用户提供有针对性的服务。 制作用户画像是为了专注和精准 使产品的服务对象更加聚焦&#xff0c;更加专注&#xff1b;根据产…

写着玩的程序:pycharm实现无限弹窗程序(非病毒程序,仅整蛊使用)

运行环境 PyCharm 2023.2.1 python3.11 具体内容 源代码 import tkinter as tk from tkinter import messagebox import threadingclass PopupGenerator:def __init__(self):self.root tk.Tk()self.root.geometry("200x120")self.root.title("无限弹窗&qu…

springboot整合MongoDB实战

目录 环境准备 引入依赖 配置yml 注入mongoTemplate 集合操作 文档操作 创建实体 添加文档 查询文档 更新文档 删除文档 环境准备 引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-da…

peer eslint-plugin-vue@“^7.0.0“ from @vue/eslint-config-standard@6.1.0

问题&#xff1a; 用vue/cli脚手架安装项目时&#xff0c;选择ESlint&#xff0c;再安装依赖包的时候&#xff0c;会报以下错误&#xff0c; 原因&#xff1a; npmV7 之前的版本遇到依赖冲突时&#xff0c;会忽视冲突&#xff0c;继续安装&#xff1b; npmV7版本开始不再自动忽…

概率论与数理统计————3.随机变量及其分布

一、随机变量 设E是一个随机试验&#xff0c;S为样本空间&#xff0c;样本空间的任意样本点e可以通过特定的对应法则X&#xff0c;使得每个样本点都有与之对应的数对应&#xff0c;则称XX&#xff08;e&#xff09;为随机变量 二、分布函数 分布函数&#xff1a;设X为随机变量…

【Linux】-对于信号章节补充的知识点,以及多线程知识的汇总

&#x1f496;作者&#xff1a;小树苗渴望变成参天大树&#x1f388; &#x1f389;作者宣言&#xff1a;认真写好每一篇博客&#x1f4a4; &#x1f38a;作者gitee:gitee✨ &#x1f49e;作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 动态规划算法&#x1f384; 如 果 你 …

数组中的内存(java)

java内存分配&#xff1a; 栈&#xff1a;方法运行时使用的内存&#xff0c;比如main方法运行&#xff0c;进入方法栈中执行 程序的主入口&#xff08;main方法&#xff09;开始执行时会进栈&#xff0c;代码执行完毕会出栈 堆&#xff1a;存储对象或者数组&#xff0c;new来…

基于Python实现人脸识别相似度对比

目录 引言背景介绍目的和意义 人脸识别的原理人脸图像获取人脸检测与定位人脸特征提取相似度计算 基于Python的人脸相似度对比实现数据集准备人脸图像预处理特征提取相似度计算 引言 背景介绍 人脸识别技术是一种通过计算机对人脸图像进行分析和处理&#xff0c;从而实现自动识…

Debian系统写Mysql时中文出现乱码无法定入的问题解决方案

原因是操作系统可能精简安装&#xff0c;没有GBK字符集&#xff0c;只有UTF8在转换或使用的时候有问题。 使用locale -a查看系统支持的字符集。正常的比较全的字符集的操作系统如下&#xff1a; 有问题的操作系统字符集如下&#xff1a; 解决方案&#xff1a; 步骤1&#…

LeetCode.670. 最大交换

题目 题目链接 分析 这道题的意思是我们只能交换一次&#xff0c;需要得到最大的数字。 我们的第一个想法就是要这个数字先变成一个数组&#xff0c;便于我们操作。 然后把数组最大的数放到第一个位置&#xff0c;如果最大的数字已经在第一个位置&#xff0c;那么就把次大的…