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

C++中IO文件输入输出知识详解和注意事项

以下内容将从文件流类体系打开模式文本与二进制 I/O随机访问错误处理性能优化等方面,详解 C++ 中文件输入输出的使用要点,并配以示例。


一、文件流类体系

C++ 标准库提供三种文件流类型,均定义在 <fstream> 中:

  • std::ifstream:输入文件流,用于从文件读取(继承自 std::istream)。
  • std::ofstream:输出文件流,用于向文件写入(继承自 std::ostream)。
  • std::fstream:读写文件流,可同时做输入和输出(继承自两者)。

它们的典型用法与标准流 (cin/cout) 类似,但需要先打开文件。


二、打开模式(std::ios_base::openmode

打开时可指定下列模式的按位或(|)组合:

模式含义
std::ios::in打开用于读操作
std::ios::out打开用于写操作
std::ios::app所有写操作均追加到文件末尾
std::ios::trunc打开时清空已有内容(默认对 ofstream 生效)
std::ios::binary二进制模式(屏蔽文本模式下的换行转换)
std::ios::ate打开后立即定位到文件末尾

示例:

std::ifstream fin("data.txt", std::ios::in);
std::ofstream fout("out.txt", std::ios::out | std::ios::trunc);
std::fstream fs("db.bin", std::ios::in|std::ios::out|std::ios::binary);

三、文本文件 I/O

1. 写入文本

  • operator<< 与格式化

    std::ofstream fout("log.txt");
    fout << "Count = " << count << '\n';
    
  • std::endl'\n'

    • std::endl 会插入换行并刷新缓冲,频繁使用有性能开销;推荐输出 '\n'

2. 读取文本

  • 按词/按行读取

    std::ifstream fin("data.txt");
    std::string word;
    while (fin >> word) { /* 按空白分隔 */ }fin.clear(); fin.seekg(0);
    std::string line;
    while (std::getline(fin, line)) { /* 读取整行,不含换行符 */ }
    
  • 混合 >>getline
    使用 >> 后会留下换行符,若紧接 getline,会读入一个空行。
    解决:每次切换前调用 fin.ignore() 跳过残留的 '\n'


四、二进制文件 I/O

当读写原始字节或 POD 结构时,选用二进制模式并使用 read/write

struct Record { int id; double value; };void writeRecords(const std::vector<Record>& recs) {std::ofstream fout("rec.bin", std::ios::out|std::ios::binary);fout.write(reinterpret_cast<const char*>(recs.data()),recs.size()*sizeof(Record));
}std::vector<Record> readRecords() {std::ifstream fin("rec.bin", std::ios::in|std::ios::binary);fin.seekg(0, std::ios::end);std::size_t size = fin.tellg() / sizeof(Record);fin.seekg(0, std::ios::beg);std::vector<Record> recs(size);fin.read(reinterpret_cast<char*>(recs.data()),size*sizeof(Record));return recs;
}
  • 注意:直接写整体 vector 只对标准布局(POD)类型安全。若含指针或非平凡类型,需循环写每个字段或序列化。

五、随机访问(定位)

  • seekg / seekp:设置读/写位置

    fin.seekg(offset, std::ios::beg|std::ios::cur|std::ios::end);
    fout.seekp(...);
    
  • tellg / tellp:返回当前位置

    auto pos = fin.tellg();
    
  • 注意:文本模式下各种平台会对换行做转换,seek/tell 不保证以字节为单位精确跳转;二进制模式下则如你所见。


六、错误处理与异常

1. 状态位检查

if (!fin) { /* 打开失败或已处于错误状态 */ }
if (fin.eof()) { /* 到达末尾 */ }
if (fin.fail()) { /* 格式错误或开关失败 */ }

2. 异常模式

fin.exceptions(std::ios::failbit | std::ios::badbit);
try {int x;fin >> x;  // 失败时抛 std::ios_base::failure
} catch (const std::ios_base::failure& e) {std::cerr << "I/O 异常: " << e.what() << "\n";
}

3. 资源管理

  • 文件流析构时会自动 close(),但若需提前关闭或检测错误,可显式:

    fin.close();
    if (fin.fail()) std::cerr<<"关闭失败\n";
    

七、性能优化

  1. 同步关闭

    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    

    可加速与 C 风格 I/O 的混用场景。

  2. 缓冲区大小

    • 默认缓冲区通常足够;若需高性能可自定义:重载流的 rdbuf()->pubsetbuf()
  3. 减少临时与拷贝

    • 尽量一次性 read/write 大块数据;
    • 对文本分词解析可用 std::string_viewstd::getline 配合 std::stringstream
  4. 避免频繁开关文件

    • 对同一文件的多次写入,宜在同一流对象上完成;若交替读写,用 fstream 且调用 seek/flush 而非反复构造流。

八、综合示例

#include <iostream>
#include <fstream>
#include <vector>
#include <string>struct Record { int id; double value; };int main() {// 1. 文本写入{std::ofstream log("app.log", std::ios::out|std::ios::app);if (!log) throw std::runtime_error("无法打开日志");log << "程序启动\n";}// 2. 文本读取与解析{std::ifstream fin("config.txt");if (!fin) {std::cerr<<"配置文件打开失败\n";} else {std::string line;while (std::getline(fin, line)) {// 跳过空行和注释if (line.empty() || line[0]=='#') continue;std::cout<<"配置: "<<line<<"\n";}}}// 3. 二进制读写std::vector<Record> recs = {{1,1.23},{2,4.56},{3,7.89}};{std::ofstream fout("data.bin", std::ios::out|std::ios::binary);fout.write(reinterpret_cast<const char*>(recs.data()),recs.size()*sizeof(Record));}{std::ifstream fin("data.bin", std::ios::in|std::ios::binary);fin.seekg(0, std::ios::end);size_t n = fin.tellg()/sizeof(Record);fin.seekg(0);std::vector<Record> buf(n);fin.read(reinterpret_cast<char*>(buf.data()), n*sizeof(Record));std::cout<<"读取 "<<buf.size()<<" 条记录\n";}return 0;
}

九、注意事项汇总

  1. 选择合适模式:文本 vs 二进制;是否截断或追加。
  2. 检查流状态:打开后、读写后、关闭后都应检查 fail() / bad() / eof()
  3. 混合读写:使用 std::fstream 并在切换前调用 flush() / seekg() / seekp()
  4. 异常安全:开启异常模式或自行检测,避免未捕获错误导致数据不一致。
  5. 平台差异:文本模式下换行转换、字符编码(如 Windows 的 CRLF)可能影响跨平台行为。
http://www.lryc.cn/news/2392664.html

相关文章:

  • centos7.6阿里云镜像各个版本介绍
  • InnoDB引擎逻辑存储结构及架构
  • KVM——CPU独占
  • 第4讲、Odoo 18 模块系统源码全解与架构深度剖析【modules】
  • pytorch简单线性回归模型
  • 在 HTML 文件中添加图片的常用方法
  • 四、web安全-行业术语
  • Kafka核心技术解析与最佳实践指南
  • Unity基础学习(十二)Unity 物理系统之范围检测
  • JVM 的垃圾回收机制 GC
  • TypeScript 针对 iOS 不支持 JIT 的优化策略总结
  • 00 QEMU源码中文注释与架构讲解
  • ansible template 文件中如果包含{{}} 等非ansible 变量处理
  • Screen 连接远程服务器(Ubuntu)
  • 路由器、网关和光猫三种设备有啥区别?
  • vscode实时预览编辑markdown
  • 2505软考高项第一、二批真题终极汇总
  • 云原生安全基础:Linux 文件权限管理详解
  • A类地址中最小网络号(0.x.x.x) 默认路由 / 无效/未指定地址
  • [嵌入式实验]实验二:LED控制
  • 6.4.2_3最短路径问题_Floyd算法
  • <PLC><socket><西门子>基于西门子S7-1200PLC,实现手机与PLC通讯(通过websocket转接)
  • day 33 python打卡
  • 开发时如何通过Service暴露应用?ClusterIP、NodePort和LoadBalancer类型的使用场景分别是什么?
  • 【机械视觉】Halcon—【六、交集并集差集和仿射变换】
  • 深度学习核心网络架构详解(续):从 Transformers 到生成模型
  • AI智能混剪视频大模型开发方案:从文字到视频的自动化生成·优雅草卓伊凡
  • allWebPlugin中间件VLC专用版之截图功能介绍
  • 【JavaSE】异常处理学习笔记
  • Scratch节日 | 六一儿童节