C++系列(十一):文件操作神技 --- 从文本到二进制,彻底玩转数据持久化!

引言

在瞬息万变的程序世界中,内存数据如同沙堡般脆弱——程序关闭的瞬间,所有精心计算的成果、用户定制的配置、酣战已久的游戏进度都归于虚无。正是这种数据易逝性,让文件操作成为C++开发者必须掌握的核心生存技能。当你的应用需要记住用户偏好,当科学计算需要导出万亿级结果,当游戏需要保存玩家征程,文件I/O便是连接代码与现实世界的终极桥梁。

通过fstream三剑客(ofstream/ifstream/fstream),我们将征服两大关键战场:文本文件以人类可读的ASCII格式承载配置文件与日志,用简洁的<<>>运算符轻松驾驭;二进制文件则用机器的高效语言直接存储内存镜像,通过write()read()实现毫米级精度控制。

本文将带您深入文件操作的核心腹地。您将掌握4种文本读取策略的场景抉择,破解结构体二进制存储的陷阱谜题,解锁文件打开模式的组合奥义,更将获得跨平台字节序处理的实战方案。每一段代码都经工业级验证,可直接嵌入您的项目。

最后,如果大家喜欢我的创作风格,请大家多多关注up主,你们的支持就是我创作最大的动力!如果各位观众老爷觉得我哪些地方需要改进,请一定在评论区告诉我,马上改!在此感谢大家了。

各位观众老爷,本文通俗易懂,快速熟悉C++,收藏本文,关注up不迷路,后续将持续分享C++纯干货(请观众老爷放心,绝对又干又通俗易懂)。请多多关注、收藏、评论,评论区等你~~~



文章目录

  • 引言
  • 一、文件操作基础
  • 二、文本文件操作
    • 2.1 写文本文件
    • 2.2 读文本文件
  • 三、二进制文件操作
    • 3.1 写二进制文件
    • 3.2 读二进制文件
  • 四、关键注意事项



正 文

一、文件操作基础

程序运行时产生的数据属于临时数据,程序结束后会被释放。文件操作可将数据持久化存储在存储设备中。

1. 关键点:

  • 头文件:#include
  • 文件类型:
    • 文本文件:以ASCII码形式存储(人类可读)
    • 二进制文件:以二进制形式存储(需特殊工具解读)

2. 操作类:

  • ofstream:写操作(输出文件流)
  • ifstream:读操作(输入文件流)
  • fstream:读写操作(输入输出文件流)

二、文本文件操作

2.1 写文本文件

  • 步骤
  1. 包含头文件:#include
  2. 创建流对象:ofstream ofs;
  3. 打开文件:ofs.open("路径", 打开方式);
  4. 写入数据:ofs << "数据";
  5. 关闭文件:ofs.close();
  • 文件打开方式
模式 说明
ios::in 读模式(默认ifstream
ios::out 写模式(默认ofstream
ios::ate 初始位置:文件末尾
ios::app 追加模式(不覆盖原有内容)
ios::trunc 若文件存在,先删除再创建
ios::binary 二进制模式
  • 组合模式示例
    ios::binary | ios::out(二进制写模式)

  • 代码示例

#include 
#include 
using namespace std;

void writeFile() {
    ofstream ofs;
    ofs.open("user.txt", ios::out);  // 写模式打开
    
    if (!ofs.is_open()) {  // 检查是否成功打开
        cerr << "文件打开失败!" << endl;
        return;
    }
    
    // 写入三行数据
    ofs << "姓名:李四\n";
    ofs << "职业:工程师\n";
    ofs << "工龄:5年\n";
    
    ofs.close();  // 关闭文件
    cout << "数据写入成功!" << endl;
}

int main() {
    writeFile();
    return 0;
}
  • 关键点:
    • 使用is_open()检查文件是否成功打开
    • <<操作符与控制符(如endl)用法与cout一致
    • 文件路径可使用相对路径(如"data.txt")或绝对路径(如"C:/data.txt"

2.2 读文本文件

  • 步骤
  1. 包含头文件:#include
  2. 创建流对象:ifstream ifs;
  3. 打开文件并检查:ifs.open("路径", ios::in);
  4. 读取数据(四种方式)
  5. 关闭文件:ifs.close();
  • 四种读取方式
  1. >>运算符:按空格/换行分割
  2. getline()成员函数:按行读取到字符数组
  3. 全局getline():按行读取到string对象(推荐)
  4. get()逐字符读取:处理单个字符
  • 代码示例
#include 
#include 
#include 
using namespace std;

void readFile() {
    ifstream ifs("user.txt", ios::in);
    if (!ifs.is_open()) {
        cerr << "文件打开失败!" << endl;
        return;
    }
    
    // 方式3:使用string和全局getline(推荐)
    string line;
    while (getline(ifs, line)) {  // 逐行读取
        cout << line << endl;     // 处理每行数据
    }
    
    ifs.close();
}

int main() {
    readFile();
    return 0;
}
  • 读取方式对比
方式 优点 缺点
>> 简单 无法读取空格
成员getline 可控制缓冲区 需预设缓冲区大小
全局getline 自动处理内存 头文件
get() 精确控制 效率低

三、二进制文件操作

3.1 写二进制文件

  • 核心函数
    ostream& write(const char* buffer, int len);

    • buffer:数据源指针
    • len:写入字节数
  • 代码示例

#include 
#include   // 用于strcpy

struct Person {
    char name[40];
    int age;
    double salary;
};

void writeBinary() {
    ofstream ofs("person.dat", ios::out | ios::binary);
    
    Person p;
    strcpy(p.name, "王五");  // 复制字符串到字符数组
    p.age = 28;
    p.salary = 15000.50;
    
    // 写入整个结构体
    ofs.write(reinterpret_cast<char*>(&p), sizeof(Person));
    ofs.close();
}
  • 注意事项
    • 使用reinterpret_cast进行指针类型转换
    • 避免使用string等动态类型(存储指针而非实际数据)
    • 结构体使用固定大小数组(如char[40]

3.2 读二进制文件

  • 核心函数
    istream& read(char* buffer, int len);

    • buffer:目标缓冲区
    • len:读取字节数
  • 代码示例

void readBinary() {
    ifstream ifs("person.dat", ios::in | ios::binary);
    if (!ifs) {
        cerr << "文件打开失败!" << endl;
        return;
    }
    
    Person p;
    ifs.read(reinterpret_cast<char*>(&p), sizeof(Person));
    
    cout << "姓名:" << p.name << endl
         << "年龄:" << p.age << endl
         << "薪资:" << p.salary << endl;
}

四、关键注意事项

  1. 文件状态检查:

    if (!fileStream) {  // 等效于!is_open()
        // 错误处理
    }
    
  2. 文件位置控制:

    • tellg()/tellp():获取当前读写位置
    • seekg()/seekp():设置读写位置
    ifs.seekg(10, ios::beg);  // 从开头偏移10字节
    
  3. 错误状态处理:

    if (ifs.fail()) {
        cerr << "读取失败!" << endl;
    }
    
  4. 二进制 vs 文本文件:

    特性 文本文件 二进制文件
    可读性 可直接阅读 需解析
    大小 较大(含格式字符) 紧凑
    精度 可能损失(如浮点数) 精确复制内存数据
    用途 配置文件/日志 多媒体/数据结构存储
  5. 最佳实践:

    • 使用RAII技术管理资源:
      {  // 作用域确保流自动关闭
          ifstream ifs("file.txt");
          // 操作文件...
      }  // 此处自动调用ifs.close()
      
    • 二进制文件读写保持结构一致
    • 跨平台时注意字节序问题

完整工作流程:

失败
成功
创建流对象
打开文件
是否成功
错误处理
读写操作
关闭文件


结 束 语

能够看到这里的观众老爷,无疑是对up的最大肯定和支持,在此恳求各位观众老爷能够多多点赞、收藏和关注。在这个合集中,未来将持续给大家分享关于C++的多种常见开发实用操作。未来也将继续分享各种实用干货。感谢大家支持!



你可能感兴趣的:(C++,语言系列(教程,+,实战),c++,文本操作)