梦想不会自己发光,真正闪耀的是那个为梦狂奔的你。献给知行的孩子们!(Eric.He著)
本教程将从C++文件操作的核心概念、标准C风格文件操作、C++风格文件流操作三个维度,全面拆解文件操作的核心用法,帮助你掌握程序与外部文件交互的关键技能。
在C++中,文件根据存储格式分为文本文件和二进制文件,两者的存储和读取方式存在本质差异:
| 特点 | 文本文件 | 二进制文件 |
|---|---|---|
| 存储格式 | 以字符编码(如ASCII)存储,可直接用记事本打开阅读 | 以二进制数据(0/1)存储,无法直接阅读,需专用程序解析 |
| 数据精度 | 存储浮点数时可能丢失精度(如3.1415926存储为字符串) | 精准存储原始数据,无精度损失 |
| 操作方式 | 按字符/行读写,适合简单文本处理 | 按字节/数据块读写,适合复杂数据(如结构体、图片) |
| 典型用途 | 配置文件、日志文件、文本文档 | 图片、视频、可执行程序、数据库文件 |
无论哪种文件操作方式,核心步骤均遵循以下流程:
⚠️ 注意:打开文件后必须检查是否成功(如文件不存在、权限不足会导致打开失败),操作完成后必须关闭文件。
freopen是C标准库函数,用于将标准输入/输出(键盘/屏幕)重定向到文件,简化输入输出操作,常用于算法竞赛、日志记录等场景。
// 重定向函数原型
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
#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;
}
#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;
}
重定向后若需彻底关闭文件,使用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风格文件操作基于FILE指针,通过fopen/fscanf/fprintf/fclose等函数实现对文件的精细化操作,兼容C语言,是最基础的文件操作方式。
// 打开文件函数原型
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;
}
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
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;
}
fclose用于关闭已打开的文件,释放系统文件句柄,避免资源泄漏。
fopen必须对应一个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++提供了更面向对象的文件流操作方式,通过ifstream(输入流)、ofstream(输出流)、fstream(读写流)实现文件操作,语法更简洁,类型更安全。
💡 提示:使用C++文件流需包含头文件#include ,并使用std命名空间。
ifstream用于从文件读取数据,支持文本/二进制模式,常用成员函数:
open():打开文件;is_open():检查文件是否打开成功;close():关闭文件;>>:按格式读取数据;getline():读取整行数据;eof():判断是否到达文件末尾。
#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;
}
ofstream用于向文件写入数据,常用成员函数:
open():打开文件;is_open():检查文件是否打开成功;close():关闭文件;<<:按格式写入数据;write():写入二进制数据;ios::app:追加模式(默认是覆盖模式)。
#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;
}
#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++进阶开发的必备技能。