CCF GESP C++ 四级考级专项讲义
主题:文件重定向与文件读写操作
一、 考点概述与大纲要求
在CCF GESP C++ 四级考试中,随着题目难度的提升,标准输入输出(cin / cout)往往无法满足大数据量或特定评测环境的需求。掌握文件的输入输出操作是信息学竞赛(OI)选手的必备基本功。
本讲核心知识点:
1. 为什么需要文件操作与重定向?
2. C++ 文件流操作 (ifstream, ofstream, fstream)
3. C 风格文件操作 (fopen, fscanf, fprintf, fclose) —— 作为拓展了解
4. 信息学竞赛中最常用的杀手锏:文件重定向 (freopen)
5. 经典实战例题讲解
二、 为什么需要文件操作?
- 标准输入输出 (
cin/cout):数据从键盘输入,输出到屏幕。缺点是如果数据量很大(比如几万行),手动输入不可能实现;屏幕输出也无法保存。 - 文件输入输出:程序直接从文件中读取数据,并将结果写入到指定文件中。
- 信息学竞赛(OI)的要求:绝大多数OJ(Online Judge)系统和考级评测时,都要求选手通过文件来读取输入数据(
.in)和输出结果(.out/.ans)。
三、 C++ 风格的文件读写操作
C++ 通过头文件 <fstream> 提供了面向对象的文件操作方式,主要涉及三个类:
1. ifstream:专用于读文件(Input File Stream)
2. ofstream:专用于写文件(Output File Stream)
3. fstream:同时支持读和写
1. 基本步骤
- 包含头文件
#include <fstream> - 创建文件流对象,并打开文件
- 进行读写操作(使用
>>和<<,或者getline()等) - 关闭文件 (
close())
2. 代码实例:C++ 文件读写
假设当前目录下有一个名为 input.txt 的文件,里面包含两个整数。我们需要读取它们,求和后写入到 output.txt 中。
#include <iostream>
#include <fstream> // 1. 包含头文件
using namespace std;
int main() {
// 2. 创建输入流对象并打开文件(用于读)
ifstream inFile("input.txt");
// 检查文件是否成功打开
if (!inFile) {
cerr << "错误:无法打开输入文件!" << endl;
return 1;
}
int a, b;
// 3. 从文件中读取数据
inFile >> a >> b;
// 关闭输入文件
inFile.close();
int sum = a + b;
// 2. 创建输出流对象并打开文件(用于写)
ofstream outFile("output.txt");
if (!outFile) {
cerr << "错误:无法打开输出文件!" << endl;
return 1;
}
// 3. 将结果写入文件
outFile << "两数之和为: " << sum << endl;
// 4. 关闭输出文件
outFile.close();
cout << "文件读写完毕,结果已写入 output.txt" << endl;
return 0;
}
四、 C 风格的文件读写操作(拓展了解)
在老代码或部分系统编程中,常使用 C 语言的 <cstdio>(即 <stdio.h>)库进行文件操作。GESP考试虽然以 C++ 为主,但了解 C 风格有助于阅读各类参考代码。
核心函数:
FILE *fopen(const char *filename, const char *mode);—— 打开文件"r":只读方式打开"w":只写方式打开(会清空原文件内容)"a":追加方式打开int fscanf(FILE *stream, const char *format, ...);—— 格式化读int fprintf(FILE *stream, const char *format, ...);—— 格式化写int fclose(FILE *stream);—— 关闭文件
代码实例:C 风格读写
#include <iostream>
#include <cstdio> // 包含C风格输入输出头文件
using namespace std;
int main() {
// 1. 打开文件用于读取
FILE *fin = fopen("input.txt", "r");
if (fin == NULL) {
printf("无法打开输入文件\n");
return 1;
}
int a, b;
// 2. 从文件读取
fscanf(fin, "%d %d", &a, &b);
// 3. 关闭文件
fclose(fin);
int sum = a + b;
// 1. 打开文件用于写入
FILE *fout = fopen("output.txt", "w");
if (fout == NULL) {
printf("无法打开输出文件\n");
return 1;
}
// 2. 写入文件
fprintf(fout, "Sum = %d\n", sum);
// 3. 关闭文件
fclose(fout);
return 0;
}
五、 信息学竞赛杀手锏:文件重定向 (freopen)
在信息学竞赛(如GESP、CSP-J/S)中,如果每一道题都要去写 ifstream、ofstream 并在代码各处修改流对象,会非常繁琐,且容易在考场上出错。
竞赛中最推荐的做法是使用 freopen 进行“文件重定向”。
1. 什么是文件重定向?
freopen 可以把标准输入(stdin,即键盘 cin)和标准输出(stdout,即屏幕 cout)重定向到指定的磁盘文件中。
* 妙处在于:你在代码中完全不需要修改任何 cin 和 cout,就像平时写本地调试代码一样!只需在 main 函数开头加上两行代码,程序就会自动从文件读入,并自动输出到文件。
2. 函数原型与用法
FILE *freopen(const char *filename, const char *mode, FILE *stream);
filename:文件名。mode:模式("r"表示读,"w"表示写)。stream:通常填stdin(输入)或stdout(输出)。
3. 竞赛标准模板代码
#include <iostream>
using namespace std;
int main() {
// 【核心技巧】文件重定向
// 把标准输入重定向到 sum.in
freopen("sum.in", "r", stdin);
// 把标准输出重定向到 sum.out
freopen("sum.out", "w", stdout);
int a, b;
// 照常使用 cin 读取(实际上是从 sum.in 中读)
cin >> a >> b;
// 照常使用 cout 输出(实际上是写入到 sum.out 中)
cout << a + b << endl;
// 竞赛中最后一般可以不写 fclose,系统会自动回收,但养成好习惯写上也可以
return 0;
}
4. 考试调试技巧(调试与提交的切换)
在本地写代码时,我们需要调试,如果加上了 freopen,屏幕上就看不到输入输出了,很不方便。因此,竞赛选手通常会使用 宏定义 来灵活切换:
#include <iostream>
using namespace std;
// 定义一个宏,平时调试时注释掉下面这行,提交时取消注释
#define LOCAL
int main() {
#ifdef LOCAL
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
int a, b;
cin >> a >> b;
cout << "结果是: " << a + b << endl;
return 0;
}
- 本地调试:不交
LOCAL,直接在控制台键盘输入,屏幕看结果。 - 考场提交/评测:加上
#define LOCAL(或者评测系统自动定义),程序无缝切换为读写指定文件。
六、 经典例题实战
题目:A+B 文件版
题目描述:
从文件 aplusb.in 中读入两个正整数 $A$ 和 $B$($1 \le A, B \le 10^9$),计算它们的和,并将结果输出到文件 aplusb.out 中。
C++ 完整解答(使用 freopen):
#include <iostream>
using namespace std;
int main() {
// 1. 重定向输入输出
freopen("aplusb.in", "r", stdin);
freopen("aplusb.out", "w", stdout);
// 2. 定义变量(注意数据范围,用long long更安全)
long long a, b;
// 3. 读取数据
if (cin >> a >> b) {
// 4. 输出数据
cout << a + b << endl;
}
return 0;
}
七、 考点总结与注意事项(避坑指南)
- 文件名拼写:考场上一定要看清题目要求的输入输出文件名(大小写、后缀名如
.in/.out),文件名拼错直接导致该题不得分(零分!)。 - 文件路径:如果不写路径(如
"input.txt"),文件默认保存在源代码同级目录下或编译运行的当前工作目录中。 - 文件关闭:使用
ifstream和ofstream时,用完一定要.close();而用freopen重定向的,系统会在程序结束时自动关闭。 - 流状态检查:在做复杂文件读写时,养成习惯用
if (!fin.is_open())来判断文件是否成功打开,防止因找不到文件而导致程序崩溃。
—— 本文来自火龙信奥(义乌睿码科技):义乌青少年信息学奥赛与编程教育平台,专注 CSP-J/S、NOIP、GESP 竞赛培训,线上线下融合教学,助力编程升学。网址:hlcoding.com