C++中IO类(iostream、fstream和sstream)知识详解和应用
一、C++ I/O 类体系概览
C++ 的 I/O 功能由一组 流(stream) 类封装,位于头文件 <iostream>
、<fstream>
、<sstream>
等。核心类别及其继承关系简图如下:
ios_base↑basic_ios<CharT,Traits>↑┌─────────┴─────────┐│ │
basic_istream basic_ostream↑ ↑istream ostream↑ ↑ifstream, istringstream ofstream, ostringstream↑ ↑
iostream
istream
:输入流;ostream
:输出流iostream
:既能输入也能输出(如std::cin/std::cout
)ifstream/ofstream/fstream
:文件流;istringstream/ostringstream/stringstream
:基于字符串缓冲的内存流。
二、常用流对象
对象 | 头文件 | 用途 |
---|---|---|
std::cin | <iostream> | 从标准输入读取 |
std::cout | <iostream> | 向标准输出写入 |
std::cerr | <iostream> | 向标准错误写入(不带缓冲) |
std::clog | <iostream> | 向标准错误写入(带缓冲) |
std::ifstream | <fstream> | 从文件读取 |
std::ofstream | <fstream> | 向文件写入 |
std::fstream | <fstream> | 同时读写文件 |
std::istringstream | <sstream> | 从内存字符串读取 |
std::ostringstream | <sstream> | 向内存字符串写入 |
std::stringstream | <sstream> | 内存中读写混合 |
三、打开模式与文件流
#include <fstream>// 打开文件写入(若不存在则创建,若存在则截断)
std::ofstream out("data.txt", std::ios::out | std::ios::trunc);// 追加写入
std::ofstream app("data.txt", std::ios::out | std::ios::app);// 读取二进制
std::ifstream in("data.bin", std::ios::in | std::ios::binary);// 读写
std::fstream fs("db.bin", std::ios::in|std::ios::out|std::ios::binary);
-
常用模式
ios::in
、ios::out
、ios::app
(尾部追加)、ios::trunc
(截断)、ios::binary
(二进制)
-
检查打开状态
if (!out.is_open()) {std::cerr << "无法打开文件\n"; }
四、格式化与操纵器(Manipulator)
#include <iostream>
#include <iomanip>double x = 123.456789;// 控制浮点精度
std::cout << std::fixed << std::setprecision(2) << x << "\n"; // 123.46// 控制宽度与对齐
std::cout << std::setw(10) << std::left << "Hello" << "|\n";// 控制进制
int n = 255;
std::cout << std::hex << n << " " << std::dec << n << "\n"; // ff 255// 重置格式
std::cout << std::defaultfloat << std::right;
<iomanip>
中常用:setw
、setfill
、setprecision
、fixed
、scientific
、hex
、dec
、boolalpha
等。
五、同步与性能注意事项
-
关闭同步
std::ios::sync_with_stdio(false); std::cin.tie(nullptr);
- 关闭与 C 标准库(
stdio
)的同步,可大幅提升cin
/cout
性能。 cin.tie(nullptr)
解除cin
对cout
的自动刷新绑定。
- 关闭与 C 标准库(
-
避免频繁刷新
std::endl
会刷新缓冲区,使用'\n'
代替可减少开销。
-
缓冲区大小
- 可通过自定义缓冲区(继承自
std::streambuf
)或调用rdbuf()->pubsetbuf()
调整。
- 可通过自定义缓冲区(继承自
六、错误处理与例外
-
状态位(
rdstate()
/good()
/eof()
/fail()
/bad()
)if (in.fail()) { /* 读取失败 */ } if (in.eof()) { /* 到达文件末尾 */ }
-
抛出例外
in.exceptions(std::ios::failbit | std::ios::badbit); try {int v;in >> v; // 失败时抛 ios_base::failure } catch (const std::ios_base::failure& e) {std::cerr << "I/O 错误: " << e.what() << "\n"; }
七、stringstream
与文本解析
#include <sstream>
#include <string>std::string line = "100,3.14,hello";
std::istringstream ss(line);int a;
double b;
std::string s;char comma;
ss >> a >> comma >> b >> comma >> s;
// a=100, b=3.14, s="hello"
- 用于将字符串分割解析为各种类型,避免手写字符串处理逻辑。
八、自定义流缓冲区
- 继承
std::streambuf
并重载底层读写函数,可实现内存、网络、压缩等自定义 I/O。 - 示例略:需重载
underflow()
(输入)、overflow()
(输出)等。
九、示例:日志类
#include <iostream>
#include <fstream>
#include <mutex>
#include <string>class Logger {std::ofstream ofs;std::mutex mtx;
public:Logger(const std::string& filename): ofs(filename, std::ios::app){if (!ofs) throw std::runtime_error("无法打开日志文件");}void log(const std::string& msg) {std::lock_guard<std::mutex> lk(mtx);ofs << msg << '\n';// 不使用 endl 以避免每次都 flush}
};int main() {Logger log("app.log");log.log("程序启动");log.log("处理完成");return 0;
}
十、注意事项汇总
- 流关闭:文件流在析构时自动关闭,也可显式调用
close()
。 - 资源泄露:异常安全时确保流对象析构,以正确释放文件句柄。
- 同步问题:多线程写同一流需加锁或使用线程安全的自定义缓冲。
- 格式状态:流对象的格式状态会保留,若在一处修改,需注意在别处可能受影响。
- Locale 设置:对数字、小数点、宽字符支持等有要求时,可使用
std::locale
或调用imbue()
。 - 二进制 I/O:读写 POD 类型时要注意对齐与字节序问题,推荐使用
read()
/write()
。