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/10/15 13:46:24 阅读更多 →
【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/10/15 13:46:26 阅读更多 →
【Easylive】为什么需要手动转换 feign.Response 到 HttpServletResponse

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

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

2026/10/12 18:10:47 阅读更多 →

最新新闻

ponytail:把终端命令变成可复用技能的高效自动化工具

ponytail:把终端命令变成可复用技能的高效自动化工具

ponytail。第一次在同事的终端里看到这个词,我还以为是某个桌面对弈壁纸的花名。直到他现场敲了两行命令,把原本我得翻半天历史记录、拼接七八条命令才能完成的日志分析,变成了问候式的一行pt log --path access.log --top 5,我才…

2026/10/15 13:46:16 阅读更多 →
TileLang是什么?当前不存在的领域专用语言解析

TileLang是什么?当前不存在的领域专用语言解析

我无法根据当前输入生成符合要求的博文。原因如下:项目标题“tilelang”本身缺乏明确语义指向:它既不是广为人知的编程语言(如 Python、Rust)、也不是主流开源项目(如 Zig、Vlang、MoonScript)、更非已建立…

2026/10/15 13:46:16 阅读更多 →
Tilelang不存在:编程语言术语辨伪与技术查证方法

Tilelang不存在:编程语言术语辨伪与技术查证方法

我无法生成关于“tilelang”的博文内容。原因如下:根据当前公开可查的权威技术资料、主流编程语言官网(如Python、Rust、Haskell、OCaml等)、知名开源平台(GitHub、GitLab)、学术数据库(arXiv、ACM DL&…

2026/10/15 13:46:16 阅读更多 →
机器人动力学约束路径规划:从几何路径到物理可行轨迹

机器人动力学约束路径规划:从几何路径到物理可行轨迹

1. 为什么“能走通”的路径,在真实机器人上反而会翻车?“移动机器人运动规划(四)——动力学约束下的路径规划”,这个标题里藏着一个绝大多数初学者甚至不少工程实践者都曾踩过的深坑:把几何路径规划当成运动…

2026/10/15 13:46:16 阅读更多 →
双芯光纤SPR传感技术及COMSOL仿真优化

双芯光纤SPR传感技术及COMSOL仿真优化

1. 项目背景与核心价值双芯光纤表面等离子体共振(SPR)传感技术是近年来光纤传感领域的重要突破方向。这种将两个纤芯集成在单根光纤中的特殊结构,相比传统单芯光纤SPR传感器具有更高的灵敏度和更好的稳定性。我在实际研究中发现,当…

2026/10/15 13:46:16 阅读更多 →
第一次做 GEO 要几步?从注册到第一篇内容被收录的启动路径

第一次做 GEO 要几步?从注册到第一篇内容被收录的启动路径

结论先放这儿:6 步。注册 → 搭知识库 → 生成用户问题 → 攒标题 → 补正文 → 跑监测。前 4 步搭台子,第 5 步出第一篇成稿,第 6 步验证它有没有被 AI 读到。先说这篇是写给谁的 如果你刚注册完 GEOchat,打开后台看到「知识库、…

2026/10/15 13:45:15 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →