C++的 I/O 流

devtools/2025/2/6 19:35:11/

本文把复杂的基类和派生类的作用和关系捋出来,具体的接口请参考相关文档

C++的 I/O 流相关的类,继承关系如下图所示

https://zh.cppreference.com/w/cpp/io

I / O 的概念:内存和外设进行数据交互称为 I / O ,例如:把数据写入磁盘,把数据显示到屏幕,把键盘的数据传到内存等等。

流的概念:可以理解为河水,有源头,有目的,按字节流动。按流传输时,不关心内容,格式,类型等等。

我们重点要掌握的是:输入输出流定义的全局对象 cout cin 等, 还有文件输入输出流,熟悉文件输入输出流相关接口。

成员变量

https://zh.cppreference.com/w/cpp/io/ios_base

我们要熟悉一下 ios_base 中维护的一些成员变量,首先就是流的打开方式

常量

解释

std::ios::app

每次写入前寻位到流结尾

std::ios::binary

以二进制模式打开

std::ios::in

为读打开

std::ios::out

为写打开

std::ios::trunc

在打开时舍弃流的内容

std::ios::ate

打开后立即寻位到流结尾

std::ios::noreplace

以独占模式打开

这里是不是有些奇怪,怎么打开流像打开文件一样?

以 Linux 系统为例,文件管理模块会把硬件设备全部抽象成文件:显示器,键盘,网卡等属于字符设备文件,存磁盘,u盘等属于块设备文件。经过虚拟文件系统对具体文件系统抽象后,上层会以统一的视角看待底层设备。

所以,这里的一层理解是:所谓的基于流的 I/O 可以理解为进程对某个文件的输入输出。比如,C++中最常用的 cin, cout, 就是对进程的0号文件描述符和1号文件描述符进行操作

文件有自己的打开方式,对应的,流也就有打开方式

视角再拉回来,ios_base 中的成员变量还有寻位相关的

常量

解释

std::ios::beg

流的开始

std::ios::end

流的结尾

std::ios::cur

流位置指示器的当前位置

还有流的状态

常量

解释

goodbit

无错误

badbit

不可恢复的流错误

failbit

输入/输出操作失败(格式化或提取错误)

eofbit

关联的输出序列已抵达文件尾


输入输出操作

std::basic_streambuf 是输入输出操作的缓冲区

https://zh.cppreference.com/w/cpp/io/basic_streambuf

std::basic_streambuf 关联的缓冲区有两类:

1. 通过操作系统的API访问的实体(文件、TCP 套接字、串行端口、其他字符设备)

2.能解读成缓冲区的对象(std::vector, std::string等)

对于输入操作来说,该缓冲区称为获取区(进程从获取区拿数据)

对于输出操作来说,该缓冲区称为放置区(进程把数据放到放置区)

std::basic_ostream 提供输出操作

https://zh.cppreference.com/w/cpp/io/basic_ostream

标准库提供六个全局 basic_ostream 对象:

在标头 <iostream> 定义

cout | wcout

写入到标准 C 输出流 stdout (全局对象)

cerr | wcerr

写入到标准 C 错误流 stderr,无缓冲 (全局对象)

clog | wclog

写入到标准 C 错误流 stderr (全局对象)

std::basic_istream 提供输入操作

https://zh.cppreference.com/w/cpp/io/basic_istream

标准库提供两个全局 basic_istream 对象:

在标头 <iostream> 定义

cin | wcin

从标准 C 输入流 stdin 读取 (全局对象)

std::basic_iostream 继承了std::basic_ostream 和 std::basic_istream ,提供输入输出操作。
https://zh.cppreference.com/w/cpp/io/basic_iostream

为了理解 std::basic_streambuf std::basic_ostream std::basic_istream 我们看如下程序,下面程序中 MyStreamBuf 是自定义的缓冲区, 封装 std::string 对象。MyStreamBuf 继承了 std::streambuf 可以重写 std::streambuf 的虚函数,std::ostream 接受一个缓冲区 MyStreamBuf 作为参数实例化对象。

注:std::ostream , std::streambuf 是 std::basic_ostream , std::basic_streambuf 的别名

下面封装缓冲区是 重写 overflow 和 xsputn 两个虚函数,可以参考std::streambuf文档

#include <iostream>
#include <streambuf>
#include <string>// 自定义流缓冲区:将输出内容存储到字符串
class MyStreamBuf : public std::streambuf {
protected:std::string buffer_;// 处理单个字符输出virtual int_type overflow(int_type c) override {if (c != traits_type::eof()) {buffer_ += traits_type::to_char_type(c);}return c;}// 处理多字符输出virtual std::streamsize xsputn(const char* s, std::streamsize n) override {buffer_.append(s, n);return n;}public:const std::string& getBuffer() const { return buffer_; }
};int main() {MyStreamBuf buf; // 实例化自定义流缓冲区std::ostream myStream(&buf); // 构造ostream,使用自定义缓冲区myStream << "Hello World! " << 42 << std::endl; // 输出到流// 获取并打印缓冲区内容std::cout << "输出流里的内容是: " << buf.getBuffer();return 0;
}

文件的输入输出流

下面我们介绍 std::basic_fstream 。 std::basic_fstream 继承关系如下所示

基类我们前文已经介绍了,ios_base 维护必要的变量, basic_istream 提供输入操作, basic_ostream 提供输出操作。

std::basic_fstream 作为派生类,添加了一些文件相关的接口,可以参考文档

https://zh.cppreference.com/w/cpp/io/basic_fstream

下面写一个小程序,可以拷贝图片或视频

#include <iostream>
#include <fstream>
using namespace std;
int main() {// 打开源文件(二进制模式)fstream inFile("C:\\Users\\34497\\Desktop\\屏幕录制 2025-01-15 213832.mp4", ios::in | ios::binary);  if (!inFile) {cerr << "无法打开源文件" << endl;return 1;}// 创建目标文件(二进制模式并清空内容)fstream outFile("C:\\Users\\34497\\Desktop\\destination.mp4", ios::out | ios::binary | ios::trunc);        if (!outFile) {cerr << "无法创建目标文件" << endl;inFile.close();return 1;}// 使用缓冲区提高读写效率const int BUFFER_SIZE = 4096;char buffer[BUFFER_SIZE];// 循环读写文件内容while (inFile.read(buffer, BUFFER_SIZE)) {outFile.write(buffer, inFile.gcount());}// 处理最后一次读取的数据if (inFile.eof()) {// 写入剩余的有效数据outFile.write(buffer, inFile.gcount());}else {// 非EOF错误处理cerr << "文件读取过程中发生错误" << endl;inFile.close();outFile.close();return 1;}// 关闭文件流inFile.close();outFile.close();cout << "拷贝完成!" << endl;   return 0;
}


http://www.ppmy.cn/devtools/156601.html

相关文章

设计模式 - 行为模式_Template Method Pattern模板方法模式在数据处理中的应用

文章目录 概述1. 核心思想2. 结构3. 示例代码4. 优点5. 缺点6. 适用场景7. 案例&#xff1a;模板方法模式在数据处理中的应用案例背景UML搭建抽象基类 - 数据处理的 “总指挥”子类定制 - 适配不同供应商供应商 A 的数据处理器供应商 B 的数据处理器 在业务代码中整合运用 8. 总…

Tomcat启动流程与前端请求处理详解

Tomcat启动流程与前端请求处理详解 一、Tomcat启动流程 Tomcat是一个Servlet容器&#xff0c;它负责将Web应用程序中的Servlet与外部HTTP请求进行交互。Tomcat启动时会加载所有的Web应用和Servlet&#xff0c;并通过扫描和反射机制将其映射到适当的Servlet类上。下面是Tomcat启…

gitlab云服务器配置

目录 1、关闭防火墙 2、安装gitlab 3、修改配置 4、查看版本 GitLab终端常用命令 5、访问 1、关闭防火墙 firewall-cmd --state 检查防火墙状态 systemctl stop firewalld.service 停止防火墙 2、安装gitlab xftp中导入安装包 [rootgitlab ~]#mkdir -p /service/tool…

MySQL知识点总结(十七)

在从属服务器上执行RESET SLAVE命令时&#xff0c;会发生哪些操作&#xff1f; RESET SLAVE命令会断开从属服务器与主服务器的连接&#xff0c;以重置从属服务器&#xff0c;具体效果如下&#xff1a;清除 master.info和relay.log资料档案库删除所有中继日志启动新的中继日志文…

pytorch实现门控循环单元 (GRU)

人工智能例子汇总&#xff1a;AI常见的算法和例子-CSDN博客 特性GRULSTM计算效率更快&#xff0c;参数更少相对较慢&#xff0c;参数更多结构复杂度只有两个门&#xff08;更新门和重置门&#xff09;三个门&#xff08;输入门、遗忘门、输出门&#xff09;处理长时依赖一般适…

Java 大视界 -- 深度洞察 Java 大数据安全多方计算的前沿趋势与应用革新(52)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

vue vscode插件推荐安装

在 VSCode 中开发 Vue&#xff0c;推荐安装以下插件&#xff1a; 核心插件 1. Volar&#xff08;Vue Language Features&#xff09; - Vue 3 官方推荐的开发工具&#xff0c;替代 Vetur。 This extension is deprecated. Use the Vue - Official extension instead. 1.Vue …

2025年2月2日(tcp3次握手4次挥手)

TCP&#xff08;三次握手和四次挥手&#xff09;是建立和关闭网络连接的标准过程&#xff0c;确保数据在传输过程中可靠无误。下面是详细解释&#xff1a; 1. 三次握手&#xff08;TCP连接建立过程&#xff09; 三次握手是为了在客户端和服务器之间建立一个可靠的连接&#x…