当前位置: 首页 > ops >正文

C++进阶:IO流

目录

  • 1. C++中的IO流
  • 2. C++处理IO型OJ题目的方式
  • 3. C++中IO类型的tie接口
  • 4. C++中的文件读写
  • 5. 自定义类型的流插入与流提取

1. C++中的IO流

  IO(Input and Output)输入输出,其含义为内存与各种设备的数据交互,既可以是屏幕显示(windows OS下默认为为控制台、Linux OS下默认为终端)也可以是键盘、磁盘等等。所有设备都是以虚拟文件的形式模拟出来从而被操作系统控制。
  C语言中提供了各种库函数来实现数据的各种输入与输出,诸如,向控制台输出printf,向指定文件中输出fprintf,将数据输出到指定字符串缓冲区sprintf。而C++中类比C语言,采用了面向对象的方式重新实现了一套用于数据IO的体系。C++的IO操作中相较于C语言来说,最关键的是对自定义类型的流插入、提取的重载兼容。
在这里插入图片描述
  C++中创建了相应的自定义类型与对象来进行对应IO操作,如<iostream>头文件中的cin(标准输入)、cout(标准输出)、cerr(标准错误)与clog(负责标准错误中日志信息或重要错误信息)。cout、cerr、clog三者对应的设备其实都是显示器终端,这三者的信息是分开存放的,以便后续有需要向文件/数据库中写入。
  C++中负责IO的对象,其基础的使用方法为流提取(operator>>)/流插入(operator<<)。最基础的负责普通IO的类实现了这两种操作,后续继承自此的类都对这两种操作进行了实现重载。

#include <fstream>// ifstream ofstream
#include <sstream>// istringstream ostringstream//C++中的IO
int main()
{//普通IO,标准输入、标准输出cout << "标准输出" << endl;	//流插入:标准输出string buff;cin >> buff;				//流提取:标准输入//文件IOofstream ofs("test.cpp", ios_base::out | ios_base::app);//向文件中插入ofs << "//";ifstream ifs("test.cpp");								//从文件中提取char ch;ifs >> ch;cout << ch << endl;//字符串缓冲区IOistringstream iss("125 320 512 750 333");int val = 0;for (int i = 0; i < 5; i++){iss >> val;//流提取时,数据会由字符会转换为相应类型cout << val * 2 << endl;}ostringstream foo;                           //outostringstream bar(std::ostringstream::ate);  //out | ate foo.str("Test string");bar.str("Test string");foo << 101;//流插入时,数据会由其他类型转换为字符类型bar << 101;cout << foo.str() << endl;//101t stringcout << bar.str() << endl;//Test string101return 0;
}

2. C++处理IO型OJ题目的方式

  当解答需要多组输入类型的OJ题目时,C语言中是通过while(scanf(...) != EOF);方式来实现的,当scanf获取到数据是其返回值为获取到数据的个数,当数据全部被获取完后scanf会返回EOF信号从而结束循环。而C++中则是通过cin流提取的方式来获取数据,那么,C++应该如何使用流提取的方式来进行多组输入呢?具体方式如下:

int main()
{string str;while (cin >> str){//...}return 0;
}

  当需要结束循环输入时,通过Ctrl + Z加换行(发出EOF信号)的组合键操作就可以结束循环。此处Ctrl + C组合键虽然同样也能够达到同样结束循环的效果,但不建议使用Ctrl + C组合键的含义为发出指定信号杀死进程。
  cin >> str的操作实际上为对函数operator>>(cin, str)的调用,operator>>函数的返回值为istream& cin自己,此类型并无法用于while循环条件的判断,只有bool类型才能进行逻辑的判断。此处的语法支持涉及到了前一章节中,自定义类型的强制类型转换。C++库中对istream类型进行了operator bool()函数的重载,使得其支持bool类型的强制类型转换,从而能够满足while循环判断的条件

class istream
{
public:operator bool(){//...}
}

3. C++中IO类型的tie接口

1. tie接口的使用:

int main() 
{cin.tie(&cout);string str;cin >> str;*cin.tie() << str << endl;// 结束绑定cin.tie(nullptr);return 0;
}

  ostream* tie (ostream* tiestr);将一个IO类型对象绑定给另一个IO类型对象。IO类型的对象都拥有此接口,使用时可以通过*IO类型对象.tie()方式获取与之绑定的IO对象,达到一种文件重定向的效果。将打开的文件绑定到cout中去,cout可以直接从文件中读取。


2. C语言缓冲区与C++缓冲区的同步:
  C语言与C++进行IO操作采用的是两种不同的体系,所以,两者使用的缓冲区也并不是同一个。 由此可知,若是C语言与C++的IO操作混用的情况下,可能会出现数据交错混乱的情况。但C++默认兼容C语言,所以在从缓冲区获取数据时,会将两者的缓冲区进行同步操作。此点虽然防止了C++与C语言缓冲区获取数据交错混乱的情况,但同样也拖慢了C++的IO操作速度。
  C++中IO类型对象有一个接口sync_with_stdio,其可以控制开关C++与C语言缓存区的同步操作。

int main()
{// C++和C不要混着用cout.sync_with_stdio(false);//关闭同步操作cout.sync_with_stdio(true);//打开同步操作return 0;
}

4. C++中的文件读写


文件的后缀标识着,文件中数据的存储方式

  • 文件的二进制读写:(window下,文件后缀.bin
      二进制的读写方式,是将文件纯粹地视为数据流以一个字节为单位进行读写。 内存中存储的数据是什么样子,就以什么样的方式读写。使用时,打开文件添加ios_basic::binary标志位。默认浏览文件时,是以文本文件的编码方式打开,因而,去浏览二进制文件时会是一片乱码。
    在这里插入图片描述
//以二进制、写模式,打开文件
ofstream ofs(_filename, ios_base::out | ios_base::binary);//以二进制方式写入,一个字节一个字节的写
int w_num = 0;
ofs.write((char*)&w_num, sizeof(w_num));//以二进制、读模式,打开文件
ifstream ifs(_filename, ios_base::in | ios_base::binary);//以二进制方式读取,一个字节一个字节的读
int r_num = 0;
ifs.read((char*)&r_num, sizeof(r_num));
  • 文件的文本读写:(windows下,文件后缀.text
      文本的读写方式,是将所有数据都已文本的形式存储或读取,读写文件的方式默认是采用文本读写的方式。 因此,使用文本方式存储与读取的文件信息是可辨认的。这里需要注意的是,文本的读写方式会忽略空格与换行符,将之视作是多个值之间的分割。
//以文本、写方式打开文件
ofstream ofs(_filename);//以文本方式写入
int w_num = 0;
ofs << w_num << endl;//以文本、读方式打开文件
ifstream ifs(_filename);//以文本方式读取
int r_num = 0;
ifs >> r_num;

  文件的文本读取中,有三个状态标志用来记录文件操作是否成功。bad()是否发生不可恢复错误(文件损坏),fail()是否发生可恢复错误(文件无法打开),eof()是否到达文件末尾。

5. 自定义类型的流插入与流提取

  • 自定义类型的文本读写:
      当采用文本读写的方式对文件进行存储或写入时,自定义类型的读写是一个仍待解决的问题。C++中流的插入提取操作本质上,是通过库中定义的默认operator<<operator>>操作来进行支持的。因此,实际上我们也可以通过自己实现重载自定义类型的operator<<operator>>函数,来使得自定义类型可以支持文本方式的读写。
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;
}
  • 自定义类型的二进制读写:
      自定义类型不支持以二进制的方式进行读写,自定义类型内部往往会有进行深拷贝的资源。对于二进制读写来说没有类型、对象等语法概念,其是以字节为单位直接读写底层数据的。因此,其对于深拷贝资源的读写只能局限于对指针的读写。
http://www.xdnf.cn/news/17902.html

相关文章:

  • 【Vibe Coding 工程之 StockAnalyzerPro 记录】- EP3.Phase 2股票列表管理功能
  • JCTools 无锁并发队列基础:ConcurrentCircularArrayQueue
  • TDengine IDMP 高级功能(4. 元素引用)
  • C# 反射和特性(关于应用特性的更多内容)
  • 解锁JavaScript性能优化:从理论到实战
  • C#WPF实战出真汁09--【消费开单】--选择菜品
  • 一次性能排查引发的Spring MVC深度思考
  • Element Plus 中 el-input 限制为数值输入的方法
  • Docker自定义镜像
  • 自动驾驶中的传感器技术24.1——Camera(16)
  • 算法训练营day53 图论④ 110.字符串接龙、105.有向图的完全可达性、106.岛屿的周长
  • Conda创建py3.10环境(股票),并且安装程序包的命令
  • 元宇宙教育:打破时空限制的学习革命
  • 汽车大灯ABD算法介绍
  • SpringAI中的模块化链式Advisor调用(源码学习)
  • B3865 [GESP202309 二级] 小杨的 X 字矩阵(举一反三)
  • Linux 多线程:线程回收策略 线程间通信(互斥锁详解)
  • linux下程序运行一段时间无端崩溃/被杀死,或者内存占用一直增大。linux的坑
  • Docker in Test:用一次性的真实环境,终结“测试永远跑不通”魔咒
  • 集成运算放大器(反向比例,同相比例)
  • C++实战
  • 静态库和动态库
  • 【leetcode】5 最长回文子串 动态规划法
  • Protues使用说明及Protues与Keil联合仿真实现点亮小灯和流水灯
  • 【Docker项目实战】使用Docker部署Notepad轻量级记事本
  • 【基础-判断】HarmonyOS提供了基础的应用加固安全能力,包括混淆、加密和代码签名能力
  • 数据结构 实现循环队列的三种方法
  • 如何在 MacOS 上安装 SQL Server
  • 搭建ktg-mes
  • 新手向:Python列表、元组、集合和字典的用法对比