欢迎光临
我们一直在努力

文件操作详解:文本文件与二进制文件(C++)

一、文件操作基础概念

1.1 核心头文件

C++ 中进行文件操作,必须包含头文件:

#include <fstream>

1.2 文件的两种类型

根据存储格式,文件分为两大类:

  • 文本文件:文件以 ASCII 码字符的形式存储在计算机中,用户可以直接打开读取、看懂内容,例如 .txt、.cpp 源文件都属于文本文件。
  • 二进制文件:文件以数据的二进制原始形式存储,用户无法直接读懂内容,例如图片、视频、可执行程序、结构体数据文件等。优点是读写效率高、体积更小。
  • 1.3 三大文件流类

    <fstream> 中提供了三个核心的流类,分别对应不同的操作场景:

    表格

    流类作用方向
    ofstream 写文件操作(输出流) 内存 → 文件
    ifstream 读文件操作(输入流) 文件 → 内存
    fstream 读写文件操作(输入输出流) 双向读写

    二、文本文件的读写

    2.1 文本文件写操作

    写文件完整步骤
  • 包含头文件 #include <fstream>
  • 创建输出流对象 ofstream
  • 打开文件,指定文件路径和打开方式
  • 向文件中写入数据
  • 操作完成后关闭文件
  • 文件打开方式

    打开方式通过 ios 命名空间下的标志位控制,多个方式可以用按位或 | 组合使用:

    表格

    打开方式功能说明
    ios::in 以读取模式打开文件(读文件时使用)
    ios::out 以写入模式打开文件(写文件时使用)
    ios::ate 打开文件后,初始光标定位在文件末尾
    ios::app 以追加模式写文件,新内容追加在文件尾部
    ios::trunc 如果文件已存在,先删除原文件,再创建新文件
    ios::binary 以二进制模式打开文件

    💡 补充:如果不指定文件路径,默认在项目的相对路径下创建 / 查找文件。

    写文件代码示例

    #include <fstream>
    #include <iostream>
    using namespace std;

    // 文本文件写操作示例
    void test_write() {
    // 1. 创建输出流对象
    ofstream ofs;

    // 2. 打开文件:路径 + 打开方式
    ofs.open("test.txt", ios::out);

    // 3. 写入数据,用法和cout一致
    ofs << "姓名:张三" << endl;
    ofs << "年龄:18" << endl;
    ofs << "职业:程序员" << endl;

    // 4. 关闭文件
    ofs.close();
    }

    int main() {
    test_write();
    return 0;
    }

    关于「不手动关闭文件」的说明

    很多人会听说 “栈上创建的文件对象可以不手动 close”,这里统一说明:

    • C++ 中,栈上的文件流对象在生命周期结束时,会通过RAII 机制自动调用析构函数,关闭文件、释放资源。
    • 但强烈建议手动调用 close ():
    • 资源泄漏风险:系统能打开的文件句柄数量有限,长期运行的程序频繁打开不关闭,会耗尽句柄资源。
    • 数据丢失风险:数据会先写入缓冲区,若程序异常退出,缓冲区数据可能没来得及刷入磁盘,造成数据丢失。

    2.2 文本文件读操作

    读文件完整步骤
  • 包含头文件 #include <fstream>
  • 创建输入流对象 ifstream
  • 打开文件,必须判断是否打开成功
  • 读取文件内容(共 4 种常用方式)
  • 关闭文件
  • 判断文件打开成功

    通过 is_open() 成员函数判断:返回 true 表示打开成功,返回 false 表示打开失败(比如文件不存在、路径错误、权限不足)。

    四种读取方式详解
    方式 1:>> 运算符(按单词读取)

    利用流提取运算符 >> 读取,以空格、换行、制表符为分隔,每次读取一个 “单词”。

    char buf[1024] = {0}; // 字符数组缓冲区
    while (ifs >> buf) { // 读到文件尾时,返回false,循环结束
    cout << buf << endl;
    }

    也可以用 string 接收,需要额外包含 #include <string>。

    方式 2:成员函数 getline(按行读取,字符数组版)

    调用流对象的 getline 成员函数,一次读取一整行。

    char buf[1024] = {0};
    // 参数1:缓冲区地址;参数2:最大读取字符数
    while (ifs.getline(buf, sizeof(buf))) {
    cout << buf << endl;
    }

    方式 3:全局 getline 函数(按行读取,string 版)

    这是开发中最推荐的文本读取方式,无需手动管理缓冲区大小,使用更灵活。

    #include <string> // 必须包含string头文件

    string buf;
    while (getline(ifs, buf)) {
    cout << buf << endl;
    }

    方式 4:get () 逐字符读取

    一次读取一个字符,直到读到文件结束符 EOF(End Of File)。

    char c;
    // ifs.get() 每次返回一个字符,读到EOF时结束
    while ((c = ifs.get()) != EOF) {
    cout << c;
    }

    特点:可以读取所有字符(包括空格、换行),但效率较低,适合特殊场景使用。

    读文件完整代码示例

    #include <fstream>
    #include <iostream>
    #include <string>
    using namespace std;

    void test_read() {
    ifstream ifs;
    ifs.open("test.txt", ios::in);

    // 必须判断打开是否成功
    if (!ifs.is_open()) {
    cout << "文件打开失败!请检查路径或文件是否存在" << endl;
    return;
    }

    // 推荐用法:按行读取,string版本
    string buf;
    while (getline(ifs, buf)) {
    cout << buf << endl;
    }

    ifs.close();
    }

    int main() {
    test_read();
    return 0;
    }

    三、二进制文件的读写

    二进制方式直接操作内存的原始字节数据,不会做 ASCII 编码转换,读写效率更高、体积更小,适合存储结构体、类对象、数值数组等数据。

    ⚠️ 注意:二进制操作必须在打开方式中加上 ios::binary,否则会按文本解析,出现乱码。

    3.1 二进制写文件

    二进制写文件使用流对象的 write 成员函数。

    • 函数原型:ostream& write(const char* buffer, int len);
    • 参数说明:
      • buffer:指向内存中待写入数据的指针
      • len:要写入的字节数
    代码示例(写入自定义类对象)

    #include <fstream>
    #include <iostream>
    using namespace std;

    // 自定义类:二进制持久化建议用char数组,不要用string
    class Person {
    public:
    char m_Name[64]; // 姓名:固定大小字符数组
    int m_Age; // 年龄
    };

    void test_binary_write() {
    // 创建流对象+打开文件,也可以分开写
    ofstream ofs("person.dat", ios::out | ios::binary);

    Person p = {"张三", 18};
    // 核心:将对象地址强转为 const char*,写入sizeof(Person)个字节
    ofs.write((const char*)&p, sizeof(Person));

    ofs.close();
    }

    ❗ 重要坑点:二进制读写自定义类型时,成员变量不要使用 string。 string 的字符串数据存在堆内存中,对象里只存了指针,写入文件只是保存了一个临时地址;下次读取时这个地址已经无效,会造成非法访问和乱码。固定大小的 char 数组是二进制持久化的最佳选择。


    3.2 二进制读文件

    二进制读文件使用流对象的 read 成员函数。

    • 函数原型:istream& read(char* buffer, int len);
    • 参数说明:
      • buffer:指向内存中接收数据的缓冲区
      • len:要读取的字节数
    代码示例(读取自定义类对象)

    void test_binary_read() {
    ifstream ifs;
    ifs.open("person.dat", ios::in | ios::binary);

    if (!ifs.is_open()) {
    cout << "文件打开失败" << endl;
    return;
    }

    Person p;
    // 核心:将对象地址强转为 char*,读取sizeof(Person)个字节
    ifs.read((char*)&p, sizeof(Person));
    cout << "姓名:" << p.m_Name << " 年龄:" << p.m_Age << endl;

    ifs.close();
    }

    四、常见问题与注意事项总结

  • 打开方式组合规则:多个标志位用 | 分隔,例如 ios::app | ios::binary 表示二进制追加模式。
  • 必须校验打开结果:永远不要假设文件一定能打开,用 is_open() 做判断是良好的编程习惯。
  • 文本 vs 二进制选型:
    • 需要人可读、跨平台文本内容 → 选文本文件
    • 存储结构体、大量数值、追求性能 → 选二进制文件
  • 换行符差异:文本模式下,Windows 系统会自动将 \\n 转换为 \\r\\n;二进制模式下不会做任何转换,原始字节读写。
  • 类型强转:write/read 只接受 char* 指针,操作其他类型时必须做强制类型转换。

  • 五、全文总结

    C++ 文件操作的核心是 <fstream> 中的三大流类,整体遵循「创建流 → 打开文件 → 读写数据 → 关闭文件」的固定流程。

    • 文本文件操作简单、可读性好,推荐用 getline(string) 按行读取;
    • 二进制文件效率高、体积小,通过 write/read 按字节操作,适合结构化数据持久化。
    赞(0)
    未经允许不得转载:171主机测评 » 文件操作详解:文本文件与二进制文件(C++)
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址