C++进阶(11):C++ IO 流
如果你在阅读过程中有任何疑问或想要进一步探讨的内容欢迎在评论区畅所欲言我们一起学习、共同成长~ 如果你觉得这篇文章还不错不妨顺手点个赞、加入收藏并分享给更多的朋友噢~1. C 语言的输入输出1.1 常用输入输出函数C 语言中最常用的输入输出方式是scanf()与printf()。scanf()从标准输入流通常是键盘读取格式化数据按照指定的格式将输入数据存储到对应的变量中。printf()将格式化的数据输出到标准输出流通常是显示器。使用时需注意宽度输出和精度输出控制。1.2 输入输出缓冲区C 语言借助相应的缓冲区来进行输入与输出输入输出缓冲区作用如下屏蔽低级 I/O 的实现低级 I/O 的实现依赖操作系统本身内核屏蔽这部分差异可使程序更具可移植性。实现 “行” 读取行为计算机本身没有 “行” 的概念通过缓冲区可定义 “行”并解析其内容返回 “行”。2. 流是什么“流” 是对有序连续且具有方向性的数据的抽象描述。C 流指信息从外部输入设备如键盘向计算机内部如内存输入以及从内存向外部输出设备显示器输出的过程。C 流的特性有序连续数据按顺序流动。有方向性分为输入流和输出流。基于 I/O 标准类库通过类对象实现输入输出操作。3. C IO 流C 中构建了一个体系庞大的类库在这个类库的继承体系里ios类是基类其他所有相关类均直接或间接派生自ios类。3.1 C 标准 IO 流3.1.1 全局流对象C 标准库提供了 4 个全局流对象cin、cout、cerr、clog。cin标准输入流键盘输入到程序属于istream类。cout标准输出流程序输出到显示器属于ostream类。cerr标准错误输出流无缓冲直接输出。clog标准日志输出流有缓冲。cout、cerr、clog是ostream类的三个不同对象应用场景不同但基本功能类似。使用时必须包含头文件iostream并引入std标准命名空间。3.1.2 关键细节3.1.2.1 缓冲机制cin为缓冲流输入数据先存入缓冲区提取时从缓冲区读取。输入错误会设置流状态字state但程序继续执行。3.1.2.2 数据类型匹配输入类型需与提取类型一致否则出错如给int变量输入字符将出错。3.1.2.3 分隔符处理空格和回车可作为数据分隔符字符型和字符串无法读取空格或回车。3.1.2.4 内置类型支持标准库已重载和运算符可直接输入输出内置类型如int、double。3.1.2.5 自定义类型支持需重载和运算符才能使用cin/cout。3.1.2.6 在线 OJ 输入输出1 IO类型的算法一般都要循环输入1单个元素循环输入适用场景读取多组单一类型数据如多组整数。​ int num; while (cin num) { // 输入整数遇EOF结束 cout 输入的数 num endl; }2多个元素循环输入适用场景读取每行包含多个数据的输入如每行输入 “姓名 年龄 分数”。string name; int age; double score; while (cin name age score) { // 按顺序读取多个元素 cout name age score endl; }3非整行字符串输入不含空格适用场景读取以空格 / 换行分隔的单词如多个独立字符串。string word; while (cin word) { // 读取单个单词遇空格/换行/EOF结束 cout 单词 word endl; }4整行字符串输入含空格适用场景读取完整句子或段落如 “Hello, world!”。string line; while (getline(cin, line)) { // 读取整行包括空格遇EOF或空行结束 if (line.empty()) break; // 可选跳过空行 cout 整行内容 line endl; }2 输出必须与题目要求完全一致包括空格、换行符、标点符号等多一个或少一个字符均可能导致错误。3 Windows 系统的 VS 系列编译器中通过输入Ctrl Z再按下Enter就可发送EOF文件结束符信号快捷终止输入循环。3.1.2.7 流对象的逻辑判断istream 对象能直接用于条件判断。若输入成功则继续执行相关操作若输入失败则停止执行相关操作。自定义类型可通过重载operator bool()函数来添加额外的逻辑判断。这些额外逻辑判断通常用于设置业务层面的结束条件。istream对象可作为逻辑条件值是因为该对象会调用operator bool函数。当流提取成功时operator bool返回true当遇到文件结束符EOF如键盘输入CtrlZ、提取类型不匹配如给int变量输入字符或流被关闭时operator bool返回false循环终止。示例#include iostream #include string using namespace std; 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) {} // 类型转换运算符定义Date对象的逻辑判断条件 explicit operator bool() const { // 假设输入_year为0时返回false return _year ! 0; } private: int _year; int _month; int _day; }; // 重载流提取运算符从输入流读取Date对象 istream operator(istream in, Date d) { in d._year d._month d._day; return in; // 返回输入流对象支持链式调用如cin d1 d2 } // 重载流插入运算符向输出流写入Date对象 ostream operator(ostream out, const Date d) { out d._year - d._month - d._day; return out; // 返回输出流对象支持链式调用如cout d endl } int main() { // 输出内置类型自动调用标准库重载的运算符 int i 1; double j 2.2; cout 内置类型输出 endl; cout 整数i i endl; cout 浮点数j j endl; // 输出自定义类型Date调用重载的运算符 Date d(2022, 4, 10); cout \n初始化的日期 d endl; // 循环输入Date对象直到输入年份为0时结束 cout \n请输入日期格式年 月 日输入0 0 0结束 endl; while (cin d) { // 用operator返回的istream对象调用operator bool // 输入成功后检查Date对象的逻辑状态_year是否为0 if (!d) { cout 检测到结束标志年份为0退出程序。 endl; break; } cout 输入的日期为 d endl; cout 请继续输入或输入0 0 0结束 endl; } return 0; }3.2 C 文件 IO 流根据数据的组织形式数据文件可分为二进制文件和文本文件。数据在内存中以二进制形式存储若不加转换输出到外存文件中就是二进制文件若要求在外存上以 ASCII 码形式存储则需在存储前转换以 ASCII 字符形式存储的文件就是文本文件。采用文件流对象操作文件的一般步骤1定义文件流对象类名用途定义语法示例ifstream只读取文件1.直接构造并打开文件ifstream 对象名(文件名,模式);2. 默认构造后打开文件ifstream 对象名;对象名.open(文件名, 模式);若未显式指定模式将默认ios_base::instd::ifstream fin(data.txt);std::ifstream fin; fin.open(data.bin, std::ios_base::binary); // 或 std::ifstream fin; fin.open(data.bin, std::ios_base::in | std::ios_base::binary);ofstream只写入文件1. 直接构造并打开文件覆盖写入ofstream 对象名(文件名,模式);2.默认构造后打开文件ofstream 对象名;对象名.open(文件名, 模式);若未显式指定模式将默认ios_base::out类似ifstreamfstream读写文件fstream 对象名(文件名, 模式);模式必须包含ios_base::in|ios_base::outstd::fstream file(data.txt, std::ios_base::in | std::ios_base::out);// 追加读写 std::fstream file(data.txt, std::ios_base::in | std::ios_base::out | std::ios_base::app);注意ifstream / ofstream / fstream均需包含头文件fstream ifstream 、ofstream 、fstream、ios_base 要展开命名空间或使用std::前缀。2打开文件成员函数open(const char* filename, ios_base::mode)。常用打开模式ios_base::in输入模式读文件。ios_base::out输出模式写文件覆盖原有内容。ios_base::app追加模式写文件内容追加到末尾。ios_base::binary二进制模式默认为文本模式。3读写文件文本读写使用和运算符需重载自定义类型运算符。二进制读写使用write()和read()成员函数按字节操作。4关闭文件调用close()成员函数。3.2.1 模拟服务器配置信息的读写#include iostream #include fstream #include string using namespace std; class Date { public: Date(int year 1, int month 1, int day 1) : _year(year), _month(month), _day(day) {} friend ostream operator(ostream out, const Date d); friend istream operator(istream in, Date d); private: int _year; int _month; int _day; }; ostream operator(ostream out, const Date d) { out d._year - d._month - d._day; return out; } istream operator(istream in, Date d) { char separator1, separator2; // 用于读取日期中的分隔符如- in d._year separator1 d._month separator2 d._day; return in; } // 服务器信息结构体 struct ServerInfo { char _address[32]; // 地址字符数组 int _port; // 端口号 Date _date; // 日期已重载IO运算符 }; // 配置管理类 class ConfigManager { public: // 构造函数初始化文件名 explicit ConfigManager(const char* filename) : _filename(filename) {} // 二进制写入文件 void WriteBin(const ServerInfo info) { ofstream ofs(_filename, ios_base::out | ios_base::binary); if (!ofs.is_open()) { // 检查文件是否打开成功 cerr Error: Failed to open file for writing (binary). endl; return; } // 写入结构体数据需保证结构体无虚函数、无动态成员否则需自定义序列化逻辑 ofs.write(reinterpret_castconst char*(info), sizeof(info)); ofs.close(); } // 二进制读取文件 void ReadBin(ServerInfo info) { ifstream ifs(_filename, ios_base::in | ios_base::binary); if (!ifs.is_open()) { cerr Error: Failed to open file for reading (binary). endl; return; } // 读取结构体数据 ifs.read(reinterpret_castchar*(info), sizeof(info)); ifs.close(); } // 文本写入文件 void WriteText(const ServerInfo info) { ofstream ofs(_filename); if (!ofs.is_open()) { cerr Error: Failed to open file for writing (text). endl; return; } // 使用流插入运算符写入数据需保证Date类已重载 ofs info._address info._port info._date endl; ofs.close(); } // 文本读取文件 void ReadText(ServerInfo info) { ifstream ifs(_filename); if (!ifs.is_open()) { cerr Error: Failed to open file for reading (text). endl; return; } // 使用流提取运算符读取数据需保证Date类已重载 ifs info._address info._port info._date; ifs.close(); } private: string _filename; // 配置文件名 }; int main() { // 初始化服务器信息 ServerInfo winfo { 192.0.0.1, // 地址 80, // 端口号 {2022, 4, 10} // 日期使用Date构造函数初始化 }; // 创建配置管理器对象二进制和文本文件 ConfigManager cf_bin(test.bin); ConfigManager cf_text(test.txt); // ---------------------- 二进制操作 ---------------------- // 写入二进制文件 cf_bin.WriteBin(winfo); cout 二进制文件写入完成。 endl; // 读取二进制文件 ServerInfo rbinfo; cf_bin.ReadBin(rbinfo); cout 二进制读取结果 endl; cout 地址 rbinfo._address endl; cout 端口 rbinfo._port endl; cout 日期 rbinfo._date endl; cout endl; // ---------------------- 文本操作 ---------------------- // 写入文本文件 cf_text.WriteText(winfo); cout 文本文件写入完成。 endl; // 读取文本文件 ServerInfo rtinfo; cf_text.ReadText(rtinfo); cout 文本读取结果 endl; cout 地址 rtinfo._address endl; cout 端口 rtinfo._port endl; cout 日期 rtinfo._date endl; return 0; }4. 简单介绍stringstream传统C语言方法如 sprintf / itoa 在进行类型转换与字符串操作时存在缓冲区溢出风险且需手动管理内存空间尤其在处理结构体数据的序列化与反序列化时不够安全便捷。stringstream 通过流式操作实现自动类型推导并利用安全的string缓冲区管理有效简化了类型转换与字符串拼接过程规避了上述风险更适用于序列化场景。4.1 头文件与类定义头文件#include sstream相关类istringstream从字符串读取数据输入流。ostringstream向字符串写入数据输出流。stringstream双向操作读写字符串。4.2 核心功能4.2.1 数值类型转字符串避免itoa()或sprintf()的缓冲区溢出问题自动推导类型。示例代码#include iostream #include sstream #include string // 包含string类型头文件 using namespace std; int main() { int a 12345678; string sa; // 定义用于存储转换结果的string对象 stringstream s; // 定义stringstream对象用于数据转换 // 第一次转换将整数a转换为字符串 s a; // 向stringstream中插入int类型数据自动格式化 s sa; // 从stringstream中提取数据到string对象sa cout 整数转字符串结果 sa endl; // ---------------------- 关键操作清空流状态和底层缓冲区 ---------------------- s.clear(); // 重置流状态标志清除可能的badbit状态 s.str(); // 清空stringstream底层维护的string对象避免残留数据影响下次转换 // ---------------------------------------------------------------------------- // 第二次转换将双精度浮点数d转换为字符串 double d 12.34; s d; // 向stringstream中插入double类型数据自动格式化 s sa; // 从stringstream中提取数据到string对象sa cout 浮点数转字符串结果 sa endl; return 0; }4.2.2 字符串拼接方便合并多个字符串或变量。示例代码#include iostream #include sstream #include string using namespace std; int main() { // 创建stringstream对象用于字符串操作 stringstream sstream; // 向流中插入多个字符串进行拼接 sstream Hello World, 你好; // 从stringstream中提取拼接后的完整字符串 string result sstream.str(); cout 拼接结果 result endl; return 0; }4.2.3 序列化与反序列化结构数据将结构体数据转为字符串如网络传输或从字符串解析回结构体。示例代码#include iostream #include sstream #include string using namespace std; class Date { public: Date(int year 1, int month 1, int day 1) : _year(year), _month(month), _day(day) {} friend istream operator(istream in, Date d); friend ostream operator(ostream out, const Date d); private: int _year; int _month; int _day; }; istream operator(istream in, Date d) { char separator1, separator2; // 用于处理日期格式中的分隔符如YYYY-MM-DD in d._year separator1 d._month separator2 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}, // 使用Date构造函数初始化日期 晚上一起看电影吧 }; ostringstream oss; // 按顺序输出结构体成员用空格分隔需注意字符串中的空格会导致反序列化问题 oss winfo._name winfo._id winfo._date winfo._msg; // 假设_msg中不含空格否则需特殊处理如转义或使用其他分隔符 string str oss.str(); cout 序列化字符串 str endl; // 反序列化字符串转结构体 ChatInfo rInfo; istringstream iss(str); // 按顺序读取数据与序列化顺序严格一致 iss rInfo._name rInfo._id rInfo._date rInfo._msg; // 检查反序列化是否成功处理可能的读取错误 if (iss.fail()) { cerr 反序列化失败输入格式错误 endl; return 1; } cout \n反序列化结果 endl; cout 姓名 rInfo._name ( rInfo._id ) endl; cout 时间 rInfo._date endl; cout 消息 rInfo._msg endl; return 0; }4.3 注意事项状态与缓冲区管理clear()重置流状态如badbit但不清空底层字符串。str()清空底层string对象避免多次转换时数据累积。安全性使用string代替字符数组避免缓冲区溢出。自动类型推导无需手动格式化减少错误风险。

相关新闻

3分钟搞定iPhone USB网络共享驱动安装:Windows用户的终极救星

3分钟搞定iPhone USB网络共享驱动安装:Windows用户的终极救星

3分钟搞定iPhone USB网络共享驱动安装:Windows用户的终极救星 【免费下载链接】Apple-Mobile-Drivers-Installer Powershell script to easily install Apple USB and Mobile Device Ethernet (USB Tethering) drivers on Windows! 项目地址: https://gitcode.com…

2026/8/1 20:57:36 阅读更多 →
【Easylive】consumes = MediaType.MULTIPART_FORM_DATA_VALUE 与 @RequestPart

【Easylive】consumes = MediaType.MULTIPART_FORM_DATA_VALUE 与 @RequestPart

【Easylive】项目常见问题解答(自用&持续更新中…) 汇总版 consumes MediaType.MULTIPART_FORM_DATA_VALUE 的作用 1. 定义请求的数据格式 • 作用:告诉 Feign 和 HTTP 客户端,这个接口 接收的是 multipart/form-data 格式的…

2026/8/1 20:57:36 阅读更多 →
【Easylive】为什么需要手动转换 feign.Response 到 HttpServletResponse

【Easylive】为什么需要手动转换 feign.Response 到 HttpServletResponse

【Easylive】项目常见问题解答(自用&持续更新中…) 汇总版 为什么需要手动转换 feign.Response 到 HttpServletResponse? feign.Response 是 Feign 客户端调用远程服务后返回的原始 HTTP 响应对象,而 HttpServletResponse 是…

2026/8/1 20:57:36 阅读更多 →

最新新闻

Django多表全文搜索实战:Haystack+Jieba+Whoosh集成与API设计

Django多表全文搜索实战:Haystack+Jieba+Whoosh集成与API设计

1. 项目概述与核心痛点最近在重构一个老旧的内部管理系统,后端用的是Django 2.2.7,前端是Vue,典型的分离架构。其中一个核心需求是全文搜索,涉及多个模型表,比如文章、用户、产品信息。技术栈选型上,我沿用…

2026/8/2 22:49:57 阅读更多 →
SharpXDecrypt:三分钟找回Xshell遗忘密码的专业解决方案

SharpXDecrypt:三分钟找回Xshell遗忘密码的专业解决方案

SharpXDecrypt:三分钟找回Xshell遗忘密码的专业解决方案 【免费下载链接】SharpXDecrypt Xshell全版本密码恢复工具 项目地址: https://gitcode.com/gh_mirrors/sh/SharpXDecrypt 你是否曾因忘记Xshell保存的服务器密码而陷入困境?当紧急需要登录…

2026/8/2 22:49:57 阅读更多 →
I2C从设备模拟:ESP32-Bit-Pirate伪装传感器与EEPROM的完整指南

I2C从设备模拟:ESP32-Bit-Pirate伪装传感器与EEPROM的完整指南

I2C从设备模拟:ESP32-Bit-Pirate伪装传感器与EEPROM的完整指南 【免费下载链接】ESP32-Bit-Pirate A Hardware Hacking Tool with Web-Based CLI That Speaks Every Protocol 项目地址: https://gitcode.com/GitHub_Trending/es/ESP32-Bit-Pirate ESP32-Bit…

2026/8/2 22:49:57 阅读更多 →
解锁3DS游戏新玩法:Mandarine-NEO独家特性与 hacks 完全解析

解锁3DS游戏新玩法:Mandarine-NEO独家特性与 hacks 完全解析

解锁3DS游戏新玩法:Mandarine-NEO独家特性与 hacks 完全解析 【免费下载链接】mandarine-neo A Citra fork with new features and hacks which are experimental and may not be present in Azahar. Continuation of Mandarine 3DS emulator. 项目地址: https://…

2026/8/2 22:49:57 阅读更多 →
OpenVR高级设置:终极SteamVR性能优化工具,轻松提升虚拟现实体验

OpenVR高级设置:终极SteamVR性能优化工具,轻松提升虚拟现实体验

OpenVR高级设置:终极SteamVR性能优化工具,轻松提升虚拟现实体验 【免费下载链接】OpenVR-AdvancedSettings OpenVR Advanced Settings Dashboard Overlay 项目地址: https://gitcode.com/gh_mirrors/op/OpenVR-AdvancedSettings 你是否曾经在Stea…

2026/8/2 22:49:57 阅读更多 →
Java Arrays.sort()自定义排序:从Comparator原理到Lambda与链式调用实战

Java Arrays.sort()自定义排序:从Comparator原理到Lambda与链式调用实战

1. 项目概述:为什么Arrays.sort()的自定义排序是Java工程师的必修课 在Java开发的日常里,排序是一个高频到几乎被忽略的基础操作。无论是处理从数据库查询出的用户列表,还是分析日志文件中的时间戳序列,排序都无处不在。而 java.…

2026/8/2 22:48:56 阅读更多 →

日新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/2 0:00:38 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/2 0:00:38 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/2 0:00:38 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/2 0:00:38 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/2 0:00:38 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/2 0:00:38 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/2 6:34:16 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/2 2:47:48 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/2 0:23:22 阅读更多 →