第 1 题|文件流头文件
使用 ifstream 和 ofstream 前,通常需要包含的头文件是( )。
A. <vector> B. <fstream> C. <cmath> D. <queue>
答案:B
解析: C++ 文件流类定义在<fstream>中。<vector>、<cmath>、<queue>分别对应动态数组、数学函数和队列等功能。
建议用时:20~25 分钟
今日目标:理解标准输入输出与文件输入输出的区别,掌握ifstream、ofstream、打开模式、正确读取循环和freopen的基本作用。
大纲定位:入门级文件与基本读写;不展开二进制文件结构、随机访问和系统级文件接口。
程序运行时,变量主要存放在内存中;程序结束后,这些临时数据通常不再保留。文件位于外部存储中,可以让数据在程序结束后继续存在。
平时最熟悉的是标准输入输出:
cin >> x; // 从标准输入读取,在线评测中通常由测试数据提供
cout << x; // 写到标准输出,评测系统据此检查答案
文件输入输出则指定文件作为数据来源或去向:
ifstream fin("input.txt");
ofstream fout("output.txt");
fin >> x;
fout << x;
现在多数 OJ 题目要求使用标准输入、标准输出。只有题目明确指定文件名时才按要求读写文件;本地调试时也可以使用文件。不能把“信息学比赛一定必须文件读写”当作普遍规则。
使用 C++ 文件流需要包含头文件:
#include <fstream>
ifstream:输入文件流,主要用于读文件;ofstream:输出文件流,主要用于写文件;fstream:可按打开方式进行读写。它们的操作习惯与 cin、cout 很像:
ifstream fin("data.txt");
ofstream fout("answer.txt");
int a, b;
fin >> a >> b;
fout << a + b << '\n';
若文件对象是局部变量,离开作用域时会自动关闭;显式调用 close() 仍能清楚表达“此处已经用完文件”,尤其在随后还要重新打开文件时很有用。
文件名写错、路径不存在或权限不足,都可能导致打开失败。可靠的程序应检查文件流状态:
ifstream fin("data.txt");
if (!fin) {
cout << "open failed\n";
return 0;
}
相对路径通常以程序运行时的当前工作目录为基准,不一定就是源代码所在目录。初赛如果给出“文件打不开”的情境,除了语法,还要考虑路径和权限。
>> 与 getline 读取方式不同fin >> x 会跳过前导空白,适合读取用空格或换行分隔的数字、单词:
int x;
fin >> x;
getline(fin, s) 读取一整行,可以保留行内空格,但不把行末换行符放进字符串:
string s;
getline(fin, s);
若先用 fin >> x,再紧接着 getline(fin, s),输入缓冲区里可能还留着上一行末尾的换行符,使第一次 getline 读到空行。可根据数据格式先用 fin.ignore(...) 处理残留换行。做题时要先判断程序采用哪种读取方式。
推荐把“读取成功”直接作为循环条件:
int x;
while (fin >> x) {
// 只有成功读到一个整数,才处理 x
}
不推荐这样写:
while (!fin.eof()) {
fin >> x;
// 这里可能在读取失败后仍错误地使用旧的 x
}
eof() 往往要在一次读取尝试失败后才会被置为真。把读取操作放进条件中,既能处理文件结束,也能处理格式不匹配等读取失败情况。
打开模式可以用 | 组合:
ios::in:读取;ios::out:写入;ios::app:追加,写入总发生在文件末尾;ios::trunc:打开时截断原内容;ios::binary:按二进制方式打开。ofstream log("log.txt", ios::app); // 在文件末尾追加
log << "new record\n";
普通的 ofstream fout("answer.txt"); 通常会以输出方式打开,并清除原有内容后从头写入。若想保留旧内容并继续追加,要明确使用 ios::app。
初赛基础题主要考模式含义。文本模式下的 <<、>> 处理的是字符形式的数据;二进制模式不等于“自动把对象正确序列化”,复杂对象的二进制存储还有更多规则,本日不展开。
freopen 是把标准流改到文件freopen 常用于本地调试或题目明确要求文件输入输出的场景:
#include <cstdio>
int main() {
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int a, b;
cin >> a >> b;
cout << a + b << '\n';
}
"r" 表示读取;"w" 表示写入并从头开始,原文件内容可能被清空;stdin 是标准输入,stdout 是标准输出。重定向应在读写操作之前完成。提交到普通 OJ 前,要按照题目要求决定是否保留;若题目要求标准输入输出,却把程序固定重定向到本地不存在的文件,评测时就可能读不到数据。
ifstream 读,ofstream 写,fstream 再看模式;>> 和 getline,注意残留换行;近五年 CSP-J 第一轮单选中没有找到可核实的文件读写直接原题,因此今天 8 题均按初赛常见设问方式编写,不标注为真题。
使用 ifstream 和 ofstream 前,通常需要包含的头文件是( )。
A. <vector> B. <fstream> C. <cmath> D. <queue>
下列主要用于从文件读取数据的对象定义是( )。
A. ofstream fin("data.txt");
B. ifstream fin("data.txt");
C. ostream fin("data.txt");
D. iostream fin("data.txt");
希望保留 log.txt 原有内容,并把新内容追加到文件末尾,合适的写法是( )。
A. ofstream out("log.txt", ios::app);
B. ifstream out("log.txt", ios::out);
C. ofstream out("log.txt", ios::in);
D. ofstream out("log.txt", ios::trunc);
要从文件中读取数量未知的一批整数,下列循环最稳妥的是( )。
A. while (!fin.eof()) { fin >> x; use(x); }
B. while (fin >> x) { use(x); }
C. while (true) { use(x); }
D. for (;;) { fin.eof(); use(x); }
关于 getline(fin, s),下列说法正确的是( )。
A. 只能读取一个不含空格的单词
B. 读取一整行,行内空格可以进入字符串,行末换行符不进入字符串
C. 只能读取整数
D. 每次都会把整个文件一次读完
假设 data.txt 的内容为:
3 5
2 10
阅读下面的程序:
#include <fstream>
using namespace std;
int main() {
ifstream fin("data.txt");
ofstream fout("result.txt");
int x, sum = 0, cnt = 0;
while (fin >> x) {
sum += x;
cnt++;
}
fout << cnt << ' ' << sum << '\n';
return 0;
}
while 循环的循环体一共执行( )次。
A. 2 B. 3 C. 4 D. 5
程序结束后,result.txt 的内容是( )。
A. 4 20 B. 4 10 C. 3 20 D. 20 4
该程序的结果写入 result.txt,不会由 cout 直接显示在标准输出中。(判断对错)
请先独立完成全部题目,并到玄武 OJ 提交今日答案。