文件重定向是指将程序的控制台输入输出改为文件输入输出。通过文件重定向,程序可以从文件中读取数据,也可以将结果写入文件,而不需要修改程序中的 cin 和 cout 语句。
使用 C++ 风格的文件操作需要添加头文件 并使用 std 命名空间。
#include <fstream>
using namespace std;使用 ifstream 创建读取变量,通过 open 方法打开文件,读取完毕后使用 close 关闭文件。
1ifstream cin; // 创建读取变量
2cin.open("in.txt"); // 打开文件
3if (!cin.is_open()) {
4 cout << "can't find file" << endl;
5}
6int number;
7cin >> number; // 读取数据
8cin.close(); // 关闭文件使用 ofstream 创建写入变量并打开输出文件,如果文件不存在则自动创建文件。
ofstream cout("out.txt"); // 创建写入变量并打开输出文件
cout << "hello" << endl; // 写入数据
cout.close(); // 关闭文件fstream 支持同时进行文件的读取和写入操作,可以选择追加写入或清空写入两种模式。
追加写入方式,即在文件末尾添加写入的内容:
fstream file("in.txt", ios::in | ios::out | ios::app);
int number;
file >> number;
file << "output";
file.close();清空写入方式,即先清空文件内容再进行写入操作:
fstream file("in.txt", ios::in | ios::out | ios::trunc);
int number;
file >> number;
file << "output";
file.close();使用 C 语言风格的文件重定向无需特别添加头文件,使用 freopen 函数即可将标准输入输出重定向到文件。
freopen("in.txt","r", stdin);
freopen("out.txt","w", stdout);这种方式的优点是代码简洁,重定向后程序中所有的 cin/scanf 和 cout/printf 都会自动从文件读写,在竞赛中较为常用。
程序异常就是程序的非编译性错误,可能是系统定义的,也可能是程序员定义的。程序的异常处理让程序在发生错误后依旧可以正常运行后续程序,提高了程序的健壮性。
异常处理包含三个关键模块:
throw 关键字抛出一个异常try 代码块包围可能抛出异常的代码,并指定一个或多个 catch 块来处理可能发生的异常catch 代码块中捕获并处理这个异常try-catch 的基本结构如下:
1try {
2 // 可能抛出异常的代码
3} catch (exception &error) {
4 // 处理特定类型的异常
5} catch (...) {
6 // 处理所有其他类型的异常
7}其中 throw 可以在 try 模块中直接使用,也可以在 try 模块调用的函数中使用。
下面展示在 try 模块中直接抛出异常的用法:
1#include <iostream>
2#include <stdexcept>
3using namespace std;
4
5int main() {
6 int a, b;
7 cin >> a >> b;
8 try {
9 if (b == 0) {
10 throw runtime_error("divide zero");
11 }
12 if (a < b) {
13 throw invalid_argument("a < b");
14 }
15 if (a > 100 || b > 100) {
16 throw invalid_argument("out of range");
17 }
18 int result = a / b;
19 cout << a << " / " << b << " = " << result << endl;
20 } catch (runtime_error &error) {
21 cout << error.what() << endl;
22 } catch (invalid_argument &error) {
23 cout << error.what() << endl;
24 } catch (...) {
25 cout << "an unknow error" << endl;
26 }
27 return 0;
28}下面展示在函数中抛出异常、在 try 模块中调用该函数的用法:
1#include <iostream>
2#include <stdexcept>
3using namespace std;
4
5int divide(int a, int b) {
6 if (b == 0) {
7 throw runtime_error("divide zero");
8 }
9 if (a < b) {
10 throw invalid_argument("a < b");
11 }
12 if (a > 100 || b > 100) {
13 throw invalid_argument("out of range");
14 }
15 int result = a / b;
16 return result;
17}
18
19int main() {
20 int a, b;
21 cin >> a >> b;
22 try {
23 int result = divide(a, b);
24 cout << a << " / " << b << " = " << result << endl;
25 } catch (runtime_error &error) {
26 cout << error.what() << endl;
27 } catch (invalid_argument &error) {
28 cout << error.what() << endl;
29 } catch (...) {
30 cout << "an unknow error" << endl;
31 }
32 return 0;
33}异常处理常与文件操作结合使用,用于处理文件打开失败等情况:
1#include <iostream>
2#include <fstream>
3#include <stdexcept>
4using namespace std;
5
6int main() {
7 try {
8 ifstream fin("in.txt");
9 if (!fin.is_open()) {
10 throw runtime_error("no file");
11 }
12 } catch (runtime_error &e) {
13 cout << e.what() << endl;
14 }
15 return 0;
16}下面通过具体例子展示文件读写和异常处理的完整操作流程。
例1:C++ 风格文件输入输出的完整流程
假设文件 in.txt 的内容为:
3
10 20 30程序需要从文件读入数据,计算总和,输出到 out.txt:
1#include <fstream>
2using namespace std;
3
4int main() {
5 // 第一步:打开输入文件
6 ifstream fin("in.txt");
7
8 // 第二步:读取数据
9 int n;
10 fin >> n; // 读到 n = 3
11 int sum = 0;
12 for (int i = 0; i < n; ++i) {
13 int x;
14 fin >> x; // 依次读到 10, 20, 30
15 sum += x;
16 }
17 fin.close(); // 第三步:关闭输入文件
18
19 // 第四步:打开输出文件并写入结果
20 ofstream fout("out.txt");
21 fout << "sum = " << sum << endl; // 写入 "sum = 60"
22 fout.close(); // 第五步:关闭输出文件
23
24 return 0;
25}1执行流程:
21. 打开 in.txt → 成功
32. 读取 n=3
43. 循环读取:x=10, sum=10 → x=20, sum=30 → x=30, sum=60
54. 关闭 in.txt
65. 打开 out.txt(不存在则自动创建)
76. 写入 "sum = 60"
87. 关闭 out.txt
9
10最终 out.txt 内容:
11sum = 60例2:C 语言 freopen 重定向的完整流程
1#include <cstdio>
2using namespace std;
3
4int main() {
5 freopen("in.txt", "r", stdin); // 将标准输入重定向到 in.txt
6 freopen("out.txt", "w", stdout); // 将标准输出重定向到 out.txt
7
8 int a, b;
9 scanf("%d%d", &a, &b); // 实际从 in.txt 读取
10 printf("%d\n", a + b); // 实际写入 out.txt
11
12 return 0;
13}执行流程:
1. freopen 将 stdin 指向 in.txt → 之后所有 scanf/cin 都从 in.txt 读取
2. freopen 将 stdout 指向 out.txt → 之后所有 printf/cout 都写入 out.txt
3. 程序中的输入输出代码无需任何修改,和控制台读写完全一样竞赛中的常用写法: 很多竞赛题目要求文件输入输出,使用 freopen 只需在程序开头加两行代码,其余代码不用改动,非常方便。例3:异常处理的执行流程
1int a = 10, b = 0;
2try {
3 if (b == 0) {
4 throw runtime_error("divide zero"); // 抛出异常
5 }
6 cout << a / b << endl; // 这行不会执行
7} catch (runtime_error &error) {
8 cout << error.what() << endl; // 捕获并处理异常
9}
10cout << "程序继续运行" << endl; // 异常处理后程序正常继续1执行流程:
21. 进入 try 块
32. 检查 b == 0 → 条件为真
43. throw 抛出 runtime_error 异常 → 立即跳出 try 块
54. a / b 这行被跳过(不会执行)
65. 进入匹配的 catch 块,输出 "divide zero"
76. catch 块执行完毕,程序继续正常运行
87. 输出 "程序继续运行"关键理解: throw 之后,try 块中剩余的代码不会执行,程序直接跳到匹配的 catch 块。异常处理完后,程序从 catch 块之后的代码继续运行。文件读写题目的解题步骤:
is_open() 或异常处理判断文件是否存在异常处理题目的解题步骤:
catch(...) 作为兜底:捕获所有未被前面 catch 块处理的异常close(),否则可能导致数据没有完整写入文件(缓冲区未刷新)freopen 后,cin/cout 已经重定向到文件,此时如果想在控制台输出调试信息需要用 cerrcatch(...) 放在前面,后面的特定类型 catch 块永远不会执行throw 之后 try 块中的代码不会执行,需要执行的清理代码应该放在 catch 块中或 try-catch 之后ifstream cin; 是为了演示方便,实际编程中建议使用不同的变量名(如 fin),避免与标准输入的 cin 混淆