C++文件操作

梦想不会自己发光,真正闪耀的是那个为梦狂奔的你。献给知行的孩子们!(Eric.He著)


  本教程将从C++文件操作的核心概念、标准C风格文件操作、C++风格文件流操作三个维度,全面拆解文件操作的核心用法,帮助你掌握程序与外部文件交互的关键技能。

教程目录导航

一、文件操作核心概述

1.1 文件类型(文本/二进制)

在C++中,文件根据存储格式分为文本文件二进制文件,两者的存储和读取方式存在本质差异:

特点 文本文件 二进制文件
存储格式 以字符编码(如ASCII)存储,可直接用记事本打开阅读 以二进制数据(0/1)存储,无法直接阅读,需专用程序解析
数据精度 存储浮点数时可能丢失精度(如3.1415926存储为字符串) 精准存储原始数据,无精度损失
操作方式 按字符/行读写,适合简单文本处理 按字节/数据块读写,适合复杂数据(如结构体、图片)
典型用途 配置文件、日志文件、文本文档 图片、视频、可执行程序、数据库文件

1.2 文件操作的基本步骤

无论哪种文件操作方式,核心步骤均遵循以下流程:

  1. 打开文件:建立程序与文件的连接,指定操作模式(读/写/追加等);
  2. 操作文件:读取文件内容到程序,或写入程序数据到文件;
  3. 关闭文件:断开程序与文件的连接,释放系统资源(必须执行,否则可能导致数据丢失)。

⚠️ 注意:打开文件后必须检查是否成功(如文件不存在、权限不足会导致打开失败),操作完成后必须关闭文件。

二、重定向操作(freopen)

freopen是C标准库函数,用于将标准输入/输出(键盘/屏幕)重定向到文件,简化输入输出操作,常用于算法竞赛、日志记录等场景。

2.1 freopen基本用法

语法格式:


// 重定向函数原型
FILE* freopen(const char* filename, const char* mode, FILE* stream);

// 参数说明:
// filename:目标文件路径(如"input.txt"、"D:/output.log")
// mode:打开模式("r"读、"w"写、"a"追加)
// stream:重定向的流(stdin标准输入、stdout标准输出、stderr标准错误)
// 返回值:成功返回指向文件的指针,失败返回NULL
        

2.2 重定向示例(输入/输出)

示例1:标准输入重定向(从文件读取数据)


#include <cstdio>
using namespace std;

int main() {
    // 将标准输入(stdin)重定向到input.txt
    FILE* fp = freopen("input.txt", "r", stdin);
    if (fp == NULL) {  // 检查重定向是否成功
        perror("文件打开失败"); // 将错误信息输出到标准错误流‌
        return 1;
    }

    // 原本scanf从键盘输入,现在从input.txt读取
    int a, b;
    scanf("%d %d", &a, &b);  // 读取input.txt中的两个整数
    printf("读取到的数值:a=%d, b=%d\n", a, b);

    // 关闭文件,释放资源
    fclose(fp);

    // 恢复标准输入(可选,若需重新从键盘输入)
    freopen("CON", "r", stdin);  // Windows系统
    //freopen("/dev/stdin", "r", stdin);  // Linux/Mac    

    return 0;
}
        

示例2:标准输出重定向(输出到文件)


#include <cstdio>
using namespace std;

int main() {
    // 将标准输出(stdout)重定向到output.txt
    FILE* fp = freopen("output.txt", "w", stdout);
    if (fp == NULL) {
        perror("文件打开失败"); // 将错误信息输出到标准错误流‌
        return 1;
    }

    // 原本printf输出到屏幕,现在写入output.txt
    printf("Hello, 文件重定向!\n");
    printf("这行内容会出现在output.txt中\n");
    for (int i = 1; i <= 5; i++) {
        printf("第%d行数据\n", i);
    }

    // 关闭文件,释放资源
    fclose(fp);

    // 恢复标准输出(可选)
    freopen("CON", "w", stdout);  // Windows系统
    //freopen("/dev/stdout", "w", stdout);  // Linux/Mac

    // 恢复后,以下内容会输出到屏幕
    printf("已恢复标准输出,这行显示在屏幕上\n");

    return 0;
}
        

2.3 fclose关闭重定向

重定向后若需彻底关闭文件,使用fclose函数释放资源:


#include <cstdio>
using namespace std;

int main() {
    FILE* fp = freopen("log.txt", "a", stdout);  // 追加模式
    if (fp == NULL) {
        perror("文件打开失败");
        return 1;
    }

    printf("追加一行日志信息\n");
    
    // 关闭文件,释放资源
    fclose(fp);  
    // 关闭后stdout失效,需重新关联屏幕
    freopen("/dev/stdout", "w", stdout);  // Linux/Mac
    // freopen("CON", "w", stdout);  // Windows

    return 0;
}
        

三、C风格文件操作(fopen系列)

C风格文件操作基于FILE指针,通过fopen/fscanf/fprintf/fclose等函数实现对文件的精细化操作,兼容C语言,是最基础的文件操作方式。

3.1 fopen打开文件

语法格式:


// 打开文件函数原型
FILE* fopen(const char* filename, const char* mode);

// 常用打开模式:
// "r":只读模式,文件必须存在,否则失败
// "w":只写模式,文件不存在则创建,存在则清空内容
// "a":追加模式,文件不存在则创建,写入内容追加到文件末尾
// "r+":读写模式,文件必须存在
// "w+":读写模式,文件不存在则创建,存在则清空
// "rb"/"wb"/"ab":二进制模式的读/写/追加
        

示例:打开文件并检查是否成功


#include <cstdio>
#include <cstdlib>  // 包含exit函数
using namespace std;

int main() {
    // 打开文本文件(只读模式)
    FILE* fp = fopen("data.txt", "r");
    if (fp == NULL) {  // 必须检查打开结果
        perror("打开文件失败");  // 输出错误原因
        exit(1);  // 终止程序
    }

    printf("文件打开成功!\n");

    // 操作文件...

    fclose(fp);  // 关闭文件
    return 0;
}
        

3.2 fscanf读取文件

fscanf用于从文件中按格式读取数据,语法与scanf一致,仅多一个FILE指针参数。

示例:读取文本文件中的数据


#include <cstdio>
using namespace std;

int main() {
    FILE* fp = fopen("score.txt", "r");
    if (fp == NULL) {
        perror("打开文件失败");
        return 1;
    }

    // 读取文件中的学生信息(姓名 年龄 成绩)
    char name[20];
    int age;
    float score;
    // 循环读取直到文件末尾(EOF:End of File)
    while (fscanf(fp, "%s %d %f", name, &age, &score) != EOF) {
        printf("姓名:%s,年龄:%d,成绩:%.1f\n", name, age, score);
    }

    fclose(fp);
    return 0;
}
        

假设score.txt内容:


张三 18 92.5
李四 19 88.0
王五 20 95.0
        

3.3 fprintf写入文件

fprintf用于按格式将数据写入文件,语法与printf一致,仅多一个FILE指针参数。

示例:写入数据到文本文件


#include <cstdio>
using namespace std;

int main() {
    // 打开文件(只写模式,不存在则创建)
    FILE* fp = fopen("student.txt", "w");
    if (fp == NULL) {
        perror("打开文件失败");
        return 1;
    }

    // 写入表头
    fprintf(fp, "学生信息表\n");
    fprintf(fp, "姓名\t年龄\t成绩\n");
    // 写入数据
    fprintf(fp, "张三\t%d\t%.1f\n", 18, 92.5);
    fprintf(fp, "李四\t%d\t%.1f\n", 19, 88.0);
    fprintf(fp, "王五\t%d\t%.1f\n", 20, 95.0);

    printf("数据写入完成!\n");

    fclose(fp);  // 关闭文件(必须执行,否则数据可能未写入)
    return 0;
}
        

3.4 fclose关闭文件

fclose用于关闭已打开的文件,释放系统文件句柄,避免资源泄漏。

核心要点:

示例:二进制文件读写+关闭


#include <cstdio>
using namespace std;

// 定义结构体
struct Student {
    char name[20];
    int age;
    float score;
};

int main() {
    // 写入二进制文件
    FILE* fp_w = fopen("student.bin", "wb");
    if (fp_w == NULL) {
        perror("打开写入文件失败");
        return 1;
    }

    Student stu = {"赵六", 17, 90.0};
    // fwrite:写入二进制数据(数据地址、单个数据大小、数据个数、文件指针)
    fwrite(&stu, sizeof(Student), 1, fp_w);
    fclose(fp_w);  // 关闭写入文件

    // 读取二进制文件
    FILE* fp_r = fopen("student.bin", "rb");
    if (fp_r == NULL) {
        perror("打开读取文件失败");
        return 1;
    }

    Student stu_read;
    // fread:读取二进制数据
    fread(&stu_read, sizeof(Student), 1, fp_r);
    printf("二进制读取:姓名=%s,年龄=%d,成绩=%.1f\n", 
           stu_read.name, stu_read.age, stu_read.score);
    fclose(fp_r);  // 关闭读取文件

    return 0;
}
        

四、C++风格文件流操作

C++提供了更面向对象的文件流操作方式,通过ifstream(输入流)、ofstream(输出流)、fstream(读写流)实现文件操作,语法更简洁,类型更安全。

💡 提示:使用C++文件流需包含头文件#include ,并使用std命名空间。

4.1 ifstream(文件输入流)

ifstream用于从文件读取数据,支持文本/二进制模式,常用成员函数:

示例:ifstream读取文本文件


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

int main() {
    // 1. 创建输入流对象并打开文件
    ifstream ifs;
    ifs.open("poem.txt", ios::in);  // ios::in:只读模式(默认)

    // 2. 检查文件是否打开成功
    if (!ifs.is_open()) {
        cerr << "文件打开失败!" << endl;
        return 1;
    }

    // 3. 读取文件内容(方式1:按行读取)
    string line;
    cout << "文件内容(按行读取):" << endl;
    while (getline(ifs, line)) {  // 读取每行直到末尾
        cout << line << endl;
    }

    // 重置文件指针(回到文件开头)
    ifs.clear();  // 清除EOF标志
    ifs.seekg(0, ios::beg);  // 指针移到开头

    // 3. 读取文件内容(方式2:按单词读取)
    cout << "\n文件内容(按单词读取):" << endl;
    string word;
    while (ifs >> word) {  // 以空格/换行分隔
        cout << word << " ";
    }
    cout << endl;

    // 4. 关闭文件
    ifs.close();

    return 0;
}
        

4.2 ofstream(文件输出流)

ofstream用于向文件写入数据,常用成员函数:

示例:ofstream写入文本文件


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

int main() {
    // 1. 创建输出流对象(方式1:构造时打开)
    ofstream ofs("log.txt", ios::out | ios::app);  // ios::app:追加模式

    // 2. 检查文件是否打开成功
    if (!ofs.is_open()) {
        cerr << "文件打开失败!" << endl;
        return 1;
    }

    // 3. 写入数据
    ofs << "===== 日志记录 =====" << endl;
    ofs << "时间:2024-05-20 15:30:00" << endl;
    ofs << "操作:用户登录" << endl;
    ofs << "状态:成功" << endl;

    // 写入变量数据
    int user_id = 1001;
    string username = "zhangsan";
    ofs << "用户ID:" << user_id << ",用户名:" << username << endl;

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

    cout << "日志写入完成!" << endl;

    return 0;
}
        

4.3 流操作综合示例(二进制读写)


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

// 定义结构体
struct Product {
    char name[30];  // 商品名
    float price;    // 价格
    int stock;      // 库存
};

int main() {
    // 1. 写入二进制文件
    Product prod = {"C++教程", 59.9, 1000};
    ofstream ofs("product.bin", ios::out | ios::binary);
    if (!ofs.is_open()) {
        cerr << "写入文件打开失败!" << endl;
        return 1;
    }
    // write:写入二进制数据(const char* 地址,字节数)
    ofs.write((const char*)&prod, sizeof(Product));
    ofs.close();

    // 2. 读取二进制文件
    Product prod_read;
    ifstream ifs("product.bin", ios::in | ios::binary);
    if (!ifs.is_open()) {
        cerr << "读取文件打开失败!" << endl;
        return 1;
    }
    // read:读取二进制数据
    ifs.read((char*)&prod_read, sizeof(Product));
    ifs.close();

    // 3. 输出读取结果
    cout << "商品信息:" << endl;
    cout << "名称:" << prod_read.name << endl;
    cout << "价格:" << prod_read.price << endl;
    cout << "库存:" << prod_read.stock << endl;

    return 0;
}
        

五、注意事项

六、总结

本教程覆盖了C++文件操作的核心场景和用法,掌握文件操作是实现程序数据持久化、与外部系统交互的关键,也是C++进阶开发的必备技能。


返回顶部