c++学习之IO流

目录

前言:

一,流的概念

二,c++的io流

输入输出流

缓冲区的同步

文件流

文件的打开

文件读写自定义类型数据

字符流

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

2. 字符串拼接

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


前言:

在了解c++的输入输出流之前,我们先来看看c语言的io流,c语言中是利用printf与scanf进行输入输出,中间利用缓冲区实现对数据的高效处理,

对于缓冲区这个我们在linux中已经了解到,所谓的printf与scanf都是底层函数open和write的封装,目的就是提供有缓冲区,使得更加高效的进行读写。

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

一,流的概念

所谓流就是流动的意思,物质从一方向流动到另一方向,是对一种有序连续具有方向性的数

据( 其单位可以是bit,byte,packet )的抽象描述。
所以输入输出流就是输入设备(如键盘)向内存输入数据,内存向输出设备(如显示器)输出数据,这个输入输出的过程就像流一样,主要也是因为有缓冲区作为流的介质。

二,c++的io流

对于c++,c++在兼容c语言的输出输出的情况下,自己也实现了一套完整的输入输入流库,在这个库中ios_base为基类,派生出了许多子类也就是输入,输出等。

其功能与c语言的输入输出功能基本一致,不过c++利用自己面向对象的特点搞了一套,因此我们学习c++的io流可以对标c语言来看:

输入输出流

ostream类是继承了父类basic_ios,其中也包含了需要成员方法,不过我们一般就用一个重载的<<,进行输出。

ostream对象的定义:

 ostream对象不能直接实例,上面是其构造的参数。

在输出流中,定义了三个输出对象:

以输出流为例: 

int main()
{//输出流类 ostreamostream out(nullptr); //我们用的cout cerr clog 都是ostream的对象cout << "hello c++"<<endl;clog << "hello c++"<<endl;cerr << "hello c++"<<endl;//其中关与ostream的成员方法也是有很多的cout.put('x');cout.put(48);cout.write("hello", 5);cout.precision(5);//设置浮点小数的精度为5return 0;
}

对于ostream与istream我们最多也都是用的他的流插入(<<)与流提取(>>), 当然他们也有很多成员方法,在涉及输入输出的详细操作时,大家可以搜索来看。

int main()
{string str;while (cin >> str){cout << str << endl;}
}

其次还有一点就是我们在算法题时,可能会遇到多组输入数据的情况,在这里涉及到输入流的返回值的问题,实际上,cin>>str的返回值还是一个cin输入流对象每次是他要作为bool判断就会调用operator bool来实现类型的转换。

在c++中,ostream是输入,istream是输出,通过继承输出输出,还得到了既可以输入也可以输出的输入输出流类iostream。 

缓冲区的同步

由于c++兼容c语言,二c++与c语言都有自己各自一套的输入输出流,两者也有各自的缓冲区,在使用时,有时候我们不管你是谁的缓冲区的,我们希望他们自己能相互兼容,比如输入整数,用cin与scanf都去输入,我们希望cin输入一个数,scanf输入一个数,他们是不一样的,之后在利用不同的输出,输出数据,不论谁的缓冲区,相互都可以输出:

int main()
{int i, j;cin >> i;scanf("%d", &j);printf("%d ",i);cout << j << endl;return 0;
}

因此c++为了兼容c的输入输出,兼容了c的缓冲区。当然我们也可以关闭掉这个缓冲区的兼容,

 通过调用sync_with_stdio(false)关闭缓冲区的兼容,在vs的平台下没什么问题,但不同的平台处理是不一样的。

文件流

 在c语言中主要用三组函数,fputc/fgetc像文件读写字符,fread/fwrite,读完文件与写文件,fscanf/fprintf格式化输入输出。

对于文件部分的读写也是与输入输出类似的:

文件输入类 ifstream  ,文件输出类 ofstream, 文件输出输出类 fstream。与输入输出流类似,文件流也有对应的文件缓冲区filebuf.

在c++中,由于面向对象的特性,这里都是类,主要的两个类文件输入ifstream与文件输出ofstream这两个类,其它向文件读写字符,字符串,格式化读写都是成员方法,c++提供了许多接供我们使用。

文件的打开

不过最基本的我们还是从创建文件来看,文件的打开有两种方式:

1.通过文件输入流或者文件输出流的构造函数来选择性地打开文件,

2.通过调用open方法代开文件,

文件打开的方式如下图:

 in以读的方式打开文件,out以写的方式打开文件,binary以二进制方式读写文件,ate在文件末尾出输出,app在文件末尾处追加,trunk,截断,在打开前清空文件内容。

通过将两项|(或)的方式,就可以实现和c语言的r,w,a的方式打开文件。

以ifstream为例:

int main()
{ifstream fp("test.txt", ifstream::out |ifstream::app);ofstream fd("test.txt",   ofstream::out|ofstream::app);fd.write("hello c++", 10);char* str=new char(10);fp.read(str,10);cout << str << endl;return 0;}

文件读写自定义类型数据

在c语言中可以使用fscanf与fprintf进行数据的读写,通过%d,%s等识别数据类型来向文件读写,在c++中没有对标的方法,而是全都放到fstream的流插入(<<)与流提取(>>)当中,通过不同的构造参数,调用不同的函数进行文件读写。

当然这也是为了自定义类型向文件读写时,通过重载<<与>>实现文件读写,也统一了文件读写数据可以都用 fstream的 流插入与流提取。

对于c++还是c语言向文件里读写数据其实都只有两种方式:

1.二进制读写。(字节流读写)

2.文本读写。

先以二进制读写为例:

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;
};//我们向文件读写的自定义数据
struct severInfo
{severInfo(){}severInfo(char str[], double x, Date tmp) :address(str), x(x), date(tmp){}char* address;double x;Date date;
};
//进行读写
class IO
{
public:IO(const string file){filename = file;}void write(const severInfo& tmp){//向文件以二进制方式写入 ofstream fp(filename, ofstream::binary | ofstream::out);fp.write((char*)&tmp, sizeof(tmp));//取地址转为char* 二进制写入}void read(const severInfo& tmp){//以读的二进制方式打开文件ifstream fp(filename, ifstream::binary | ifstream::in);fp.read((char*)&tmp, sizeof(severInfo));}private:string filename;
};int main()
{IO test("test.txt");severInfo tmp((char*)"192.168.1.1", 10.5, Date(2023, 1, 1));//此时写入二进制数据到文件当中test.write(tmp);severInfo info;//将读来的二进制数据存放会info中test.read(info);return 0;
}

通过存入数据的二进制(地址),在以二进制方式读取出来,实现自定义类型的读写。

但文件中是二进制数据。

其次二进制读写数据要注意不要用,数据不要用容器,因为如果时容器的话,一般封装起来不仅仅是我们要的数据,如string 里面还有capacity, size等参数,一般二进制读取数据就是内置类型的数据,或者封装起来的内置类型的数据。

文本读写

文本读写的本质就是转化成字节流,即字符串。因此我们需要很多的类型转化,好处就是文件可以看得见,坏处就是更加麻烦。

在c语言我们可以使用sprintf,sscanf将其他类型转化为字符串,c++中使用to_string来转化。

class Date
{friend ostream& operator << (ostream& out, const Date& d);friend istream& operator >> (istream& in, Date& d);//friend ofstream& operator << (ofstream& out, const Date& d);//friend ifstream& operator >> (ifstream& 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;
}//ofs << winfo._date;
ostream& operator << (ostream& out, const Date& d)
{out << d._year << " " << d._month << " " << d._day;return out;
}//我们向文件读写的自定义数据
struct severInfo
{severInfo(){}severInfo(char str[], double x, Date tmp) :address(str), x(x), date(tmp){}char* address;double x;Date date;
};class TEXTIO
{
public:TEXTIO(const string file){filename = file;}void write(const severInfo& tmp){//向文件文本方式写入 ofstream fp(filename, ofstream::out | ofstream::trunc);fp << tmp.address<<endl;fp << tmp.date<<endl;fp << tmp.x << endl;}//这里自定义类型Date需要重载>> 和 <<istream& operator >> (istream& in, Date& d)//这里的ofstream与ifstream都是继承istream与ostreamvoid read(const severInfo& tmp){ifstream fp(filename);fp >> tmp.address;fp >> tmp.x;fp >> tmp.date;}private:string filename;
};int main()
{severInfo info((char*)"192.168.1.1", 1.1, Date(2023, 1, 1));TEXTIO test("test.txt");//文本写test.write(info);severInfo tmp;//文本读test.read(tmp);
}

字符流

C 语言中,如果想要将一个整形变量的数据转化为字符串格式,如何去做?
1. 使用 itoa() 函数
2. 使用 sprintf() 函数
但是两个函数在转化时,都得 需要先给出保存结果的空间 ,那空间要给多大呢,就不太好界定,
而且 转化格式不匹配时,可能还会得到错误的结果甚至程序崩溃 。‘

对标于c语言的sprintf与sscanf,字节流的输入输出,c++也提供了字节流的输入与输出。

istringstream为字符输入,ostringstream为字符输出,stringstream是继承了输入输出,stringbuf为字符缓冲区。

使用方法与上面的文件流类似,当然字符流中的输入输出也都提供了一系列的成员方法,

如str,=等。除了自身的成员函数,当然继承的也可以使用。

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

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

int main()
{stringstream str;int a = 10;string tmp;//将其他类型的数据输出为字符型str << a;//再将该数据输入到string对象中str >> tmp;cout << tmp << endl;cout<<str.str();//返回当前字符流的副本str.clear();//清空字符缓冲区return 0;
}

2. 字符串拼接

给当前字符输入其他字符,使得字符串拼接起来:
int main()
{stringstream str;// 将多个字符串放入 str 中//先将两个字符连接起来,即都输出到str当中str << 20;str << "个苹果";str << 10;str << "个香蕉";cout << "开始" << str.str() << endl;str.str("");//修改副本为空字符str << 5;str << "个橘子";cout << "最后" << str.str() << endl;return 0;
}

可以看到对于stringstream,它自身对象就是一个缓冲区,临时字符串,可以拼接我们输出的字符

,对于内置类型,使用str方法获取它里面的临时字符串,当然也可以此时输入到一个字符串对象当中,用以存储。

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

所谓的序列化与反序列化其实就是将其他类型包括自定义类型的数据转化为字符串,或者反之,将字符串转化为对应类型的数据。
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){}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;
}
struct ChatInfo
{string name; int id;Date 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;//反序列化// 字符串解析成ChatInfo对象ChatInfo tmp;istringstream iss(str);iss >> tmp.name >> tmp.id >> tmp.date >> tmp.msg;return 0;
}
注意:
1. stringstream 实际是在其底层维护了一个 string 类型的对象用来保存结果
2. 多次数据类型转化时,一定要用 clear() 来清空,才能正确转化 ,但 clear() 不会将
stringstream 底层的 string 对象清空。
3. 可以 使用 s. str("") 方法将底层 string 对象设置为 "" 空字符串
4. 可以 使用 s.str() 将让 stringstream 返回其底层的 string 对象
5. stringstream 使用 string 类对象代替字符数组,可以避免缓冲区溢出的危险,而且其会对参
数类型进行推演,不需要格式化控制,也不会出现格式化失败的风险 ,因此使用更方便,更
安全。

 

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

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

相关文章

SpringBoot异常处理和单元测试

学习目标 Spring Boot 异常处理Spring Boot 单元测试 1.SpringBoot异常处理 1.1.自定义错误页面 SpringBoot默认的处理异常的机制&#xff1a;SpringBoot 默认的已经提供了一套处理异常的机制。一旦程序中出现了异常 SpringBoot 会向/error 的 url 发送请求。在 springBoot…

c语言->学会offsetof宏计算结构体相对偏移量

前言 ✅作者简介&#xff1a;大家好&#xff0c;我是橘橙黄又青&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;橘橙黄又青-CSDN博客 目的&#xff0c;学习offsetof宏计算结构体相对偏移量 1.offsetof宏 来我们看图…

vector讲解

在学习玩string后我们开始学习vector&#xff0c;本篇博客将对vector进行简单的介绍&#xff0c;还会对vector一些常用的函数进行讲解 vector的介绍 实际上vector就是一个数组的数据结构&#xff0c;但是vector是由C编写而成的&#xff0c;他和数组也有本质上的区别&#xff…

2.机器学习-K最近邻(k-Nearest Neighbor,KNN)分类算法原理讲解

2️⃣机器学习-K最近邻&#xff08;k-Nearest Neighbor&#xff0c;KNN&#xff09;分类算法原理讲解 个人简介一算法概述二算法思想2.1 KNN的优缺点 三实例演示3.1电影分类3.2使用KNN算法预测 鸢(yuan)尾花 的种类3.3 预测年收入是否大于50K美元 个人简介 &#x1f3d8;️&…

flink部署模式介绍

在一些应用场景中&#xff0c;对于集群资源分配和占用的方式&#xff0c;可能会有特定的需求。Flink 为各种场景提供了不同的部署模式&#xff0c;主要有以下三种&#xff0c;它们的区别主要在于&#xff1a; 集群的生命周期以及资源的分配方式&#xff1b;应用的 main 方法到…

XXL-Job的搭建接入Springboot项目(详细)

一、XXL-Job介绍 XXL-Job 是一款开源的分布式任务调度平台&#xff0c;由 Xuxueli&#xff08;徐雪里&#xff09;开发。它基于 Java 技术栈&#xff0c;提供了一套简单易用、高可靠性的任务调度解决方案。 XXL-Job 的主要作用是帮助开发者实现定时任务的调度和执行。它可以用…

2024年轻人返乡创业潮,外卖平台市场需求是怎么样的?

目前&#xff0c;县域经济正面临着几大利好。“返乡就业、返乡创业和告老还乡”现象越发普遍&#xff0c;这不仅在小县城中有所体现&#xff0c;同样在乡镇中也呈现出同样的趋势。一些产业链和工厂纷纷下沉到乡镇&#xff0c;带来了更多的就业机会。这不仅能够吸引年轻人回乡就…

Spring Boot 4.0:构建云原生Java应用的前沿工具

目录 前言 Spring Boot简介 Spring Boot 的新特性 1. 支持JDK 17 2. 集成云原生组件 3. 响应式编程支持 4. 更强大的安全性 5. 更简化的配置 Spring Boot 的应用场景 1. 云原生应用开发 2. 响应式应用程序 3. 安全性要求高的应用 4. JDK 17的应用 总结 作…

CRM系统--盘点五大CRM客户管理系统

在当今市场经济中&#xff0c;销售工作的重要性日益凸显&#xff0c;有效的客户管理成为了提升销售业绩的关键因素。面对日新月异的市场环境和客户需求的多样化&#xff0c;销售人员通常会面临以下问题&#xff1a; 接到了新的销售任务&#xff0c;该如何选择和确定目标客户&am…

API协议设计的十种技术

文章目录 前言一、REST二、GraphQL三、gRPC&#xff08;google Remote Procedure Calls&#xff09;四、Webhooks五、服务端的事件发送——SSE&#xff08;Server-sent Events&#xff09;六、EDI&#xff08;Electronic Data Interchange&#xff09;七、面向API 的事件驱动设…

Visual Studio2022实用使用技巧集

前言 对于.NET开发者而言Visual Studio是我们日常工作中比较常用的开发工具&#xff0c;掌握一些Visual Studio实用的搜索、查找、替换技巧可以帮助我们大大提高工作效率从而避免996。 Visual Studio更多实用技巧 https://github.com/YSGStudyHards/DotNetGuide 代码和功能搜…

Verilog基础:强度建模与net型信号的多驱动问题(三)

相关阅读 Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm1001.2014.3001.5482 四、一般情况下的net型信号的线与组合&#xff08;线网多驱动&#xff09; 在Verilog基础&#xff1a;强度建模与net型信号的多驱动问题&#xff08;二&#xff0…

如何在Linux部署JumpServer堡垒机并实现远程访问本地服务

文章目录 前言1. 安装Jump server2. 本地访问jump server3. 安装 cpolar内网穿透软件4. 配置Jump server公网访问地址5. 公网远程访问Jump server6. 固定Jump server公网地址 前言 JumpServer 是广受欢迎的开源堡垒机&#xff0c;是符合 4A 规范的专业运维安全审计系统。JumpS…

如何使用支付宝沙箱环境本地配置模拟支付并结合内网穿透远程调试

文章目录 前言1. 下载当面付demo2. 修改配置文件3. 打包成web服务4. 局域网测试5. 内网穿透6. 测试公网访问7. 配置二级子域名8. 测试使用固定二级子域名访问 正文开始前给大家推荐个网站&#xff0c;前些天发现了一个巨牛的 人工智能学习网站&#xff0c; 通俗易懂&#xff…

如何自己实现一个Spring Boot Starter

现在很多开源的组件都会提供对应的 springboot-starter 包给我们去用&#xff0c;要做一个 starter 包并不难。参照Spring内置的实现就好了&#xff1a; 1、在工程里引入 starter 打包相关的依赖。 2、在我们工程内建 spring.factories 文件&#xff0c;编写我们配置类的全限类…

ubuntu源码安装MySQL

mysql下载路径 创建新数组 mysql sudo groupadd mysql# 创建用户 mysql ,指定属组为 mysql&#xff0c;禁止其登录 # --no-create-home选项&#xff0c;创建用户时不会自动创建主目录 sudo adduser --system --no-create-home --ingroup mysql --shell /sbin/nologin mysql创…

安卓Spinner文字看不清

Holo主题安卓13的Spinner文字看不清&#xff0c;明明已经解决了&#xff0c;又忘记了。 spinner.setOnItemSelectedListener(new Spinner.OnItemSelectedListener() {public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {TextView textV…

基于CLIP4Clip的DRL的WTI模块实现

关于DRL的WTI模块&#xff1a; Weighted Token-wise Interaction&#xff1a; 直觉上&#xff0c;并非所有的单词和视频帧都同等重要。我们提供一种自适应方法&#xff0c;来调整每个标记的权重大小&#xff1a; 注&#xff1a;其中两个f函数都是MLP和softmax构成。 WTI的算…

网络安全的信息收集方法有哪些?

网络安全攻击中的信息收集是攻击者为了了解目标系统的弱点、配置、环境和潜在的防御措施而进行的活动。以下是一些常见的信息收集手段&#xff1a; 开放网络资源查询&#xff1a; 使用搜索引擎查找关于目标组织的信息&#xff0c;包括新闻稿、社交媒体帖子、官方网站等。通过W…

140:vue+leaflet加载here地图(v2软件多种形式)

第140个 点击查看专栏目录 本示例介绍如何在vue+leaflet中添加HERE地图(v2版本的软件),并且含多种的表现形式。包括地图类型,文字标记的设置、语言的选择、PPI的设定。 v3版本和v2版本有很大的区别,关键是引用方法上,请参考文章尾部的API链接。 直接复制下面的 vue+leaf…