CC++ & Algorithm

C++文件读写(fstream)——像写日记一样读写文件

较难19
语言版本:C++Python
概述:用fstream类创建文件对象,像用cin、cout一样从文件读、往文件写。

用 fstream 读写文件——像管理日记本一样轻松存取数据

你有没有想过,程序运行完之后,数据怎么保存下来呢?比如游戏中的最高分、每天记的账本、班级的考试成绩……这些数据不能只存在内存里,因为关掉程序就没了。这时候就需要文件来帮忙。C++ 里的 fstream 就像一本可以反复翻看的日记本——你可以翻开它(打开文件),在上面写字(写入数据),或者读它以前写的内容(读取数据)。学会了它,你的程序就能把数据“记住”啦!

准备工作:认识三个“文件专家”

要使用 fstream,先要包含头文件 <fstream>。它带来了三个好兄弟:

  • ifstream(in file stream):专门用来文件,就像你打开日记本只看不写。
  • ofstream(out file stream):专门用来文件,就像你在日记本上写字(但可能会擦掉旧字)。
  • fstream:既能读又能写,最全能,但使用时要注意模式。

基本四步走:打开 → 读写 → 关闭

不管哪个类,使用流程都一样:

  1. 创建对象:比如 ifstream fin;(创建了一个读文件对象)。
  2. 打开文件:用 open(文件名, 模式),比如 fin.open("data.txt");
  3. 读写数据:像用 cin 一样读(fin >> 变量),像用 cout 一样写(fout << 数据)。
  4. 关闭文件fin.close();,就像合上日记本,别让它一直敞着。

例子1:读文件中的两个数并求和

假设 numbers.txt 文件里有 10 和 20(用空格或换行隔开),下面程序读出来算和:

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

int main() {
    ifstream fin;
    fin.open("numbers.txt");          // 打开日记本

    int a, b;                         // 两个数字
    fin >> a >> b;                    // 从文件里读,就像从键盘输入一样

    fin.close();                      // 合上日记本
    cout << "和是:" << a + b << endl;
    return 0;
}

例子2:写一句话到文件

#include <fstream>
using namespace std;

int main() {
    ofstream fout;
    fout.open("hello.txt");           // 新建或打开日记本(如果不存在会创建)
    fout << "Hello, GESP!";           // 往日记本里写一行字
    fout.close();                     // 合上日记本
    return 0;
}

打开模式:控制“日记本”的读写行为

打开文件时,第二个参数可以指定模式,告诉计算机你想怎么用这本日记本。常用模式有:

模式含义生活类比
ios::in读模式(ifstream 默认自带)只翻开看,不动笔
ios::out写模式(ofstream 默认自带)翻开写字,但会擦掉旧页的内容
ios::app追加模式,写在末尾,不擦旧内容在日记本末尾接着写
ios::ate打开后直接定位到文件末尾一翻开就跳到最后一页
ios::trunc如果文件存在,清空它把整本日记撕掉,重新写

多个模式可以组合,用 | 连接。例如:

fstream fstr;
fstr.open("data.txt", ios::in | ios::out);   // 既能读又能写

生活小例子

  • 你想记录每天的零花钱收入,用 ios::app 追加,这样不会把昨天的记录弄丢。
  • 你要重新制定考试目标,用 ios::out 覆盖旧文件,只留最新计划。

每次打开都要“体检”:检查是否成功

就像拿到一本日记本要先看看它有没有缺页,打开文件后一定要检查是否成功了。如果文件名写错、文件路径不对或者磁盘满了,打开就会失败。如果不检查,程序可能会乱读乱写,甚至崩溃。

检查的方法有两种:

if (!fin) {   // 如果 fin 是“假”(打开失败)
    cout << "文件打开失败!" << endl;
    return 1;   // 退出程序,返回非0表示出错
}

或者:

if (!fin.is_open()) {
    cout << "文件打开失败!" << endl;
    return 1;
}

新手最容易忘的就是这一步,结果程序跑到一半发现读不到数据,闹出“灵异”bug。

新手容易犯的几个错误

  1. 忘记关闭文件
    打开后不 close(),程序运行期间文件一直被占用,其他程序可能无法读写。如果写文件,数据可能还留在缓冲区没真正存到磁盘。解决办法:成对使用 openclose,可以用“打开→处理→关闭”的思维。

  2. 路径写错
    "data.txt" 默认在程序所在的文件夹(当前目录)。如果文件在别的文件夹,要写完整路径,如 "C:\\myfolder\\data.txt"(Windows 用双反斜杠)。最好把文件放在项目文件夹下。

  3. 模式用错
    ofstream 打开一个已有文件,默认会清空它(ios::outios::trunc 效果)。如果想保留旧内容只追加,要用 ios::app
    例如:

    ofstream fout;
    fout.open("score.txt", ios::app);   // 追加在末尾
    
  4. 读不到数据就乱用变量
    如果文件是空的,或者已经读到末尾,再 fin >> x 会失败,变量保持原来的值(或未定义)。可以用 while (fin >> x) 循环读取直到结束。

  5. 混合读写顺序混乱
    fstream 同时读写时,注意文件指针的位置。写完想读,可能需要先 seekg 或关闭重开。简单起见,一般情况下只用 ifstreamofstream 一种功能,避免混淆。

完整示例:读取全班考试成绩并计算平均分

假设有一个 scores.txt 文件,内容如下(每行一个同学的成绩,可能有多个):

90
85
72
98

我们要读取所有成绩,计算平均分并输出,同时把每位同学的成绩单独写入一个新文件 report.txt

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

int main() {
    ifstream fin;
    fin.open("scores.txt");            // 打开成绩文件
    if (!fin) {                        // 检查是否打开成功
        cout << "无法打开 scores.txt!" << endl;
        return 1;
    }

    int score;                         // 存放每个成绩
    int sum = 0;                       // 总分
    int count = 0;                     // 人数

    while (fin >> score) {             // 循环读取,直到文件末尾
        sum += score;                  // 累加总分
        count++;                       // 人数加1
        cout << "读取到成绩:" << score << endl;
    }
    fin.close();                       // 读完关闭输入文件

    if (count == 0) {
        cout << "文件为空,没有成绩。" << endl;
        return 1;
    }

    double average = (double)sum / count;   // 平均分(注意转成浮点数)
    cout << "总分:" << sum << ",人数:" << count << endl;
    cout << "平均分:" << average << endl;

    // 把平均分写入 report.txt(覆盖方式)
    ofstream fout;
    fout.open("report.txt");           // 创建或覆盖报告文件
    if (!fout) {
        cout << "无法创建 report.txt!" << endl;
        return 1;
    }
    fout << "全班成绩统计" << endl;
    fout << "人数:" << count << endl;
    fout << "总分:" << sum << endl;
    fout << "平均分:" << average << endl;
    fout.close();                      // 关闭输出文件

    cout << "统计信息已写入 report.txt" << endl;
    return 0;
}

运行结果(假设 scores.txt 内容如上):

读取到成绩:90
读取到成绩:85
读取到成绩:72
读取到成绩:98
总分:345,人数:4
平均分:86.25
统计信息已写入 report.txt

拓展一步:还能做什么?

  • 读取整行文本:用 getline(fin, 字符串) 可以读取包含空格的整行内容,比如读取姓名、地址。
  • 二进制文件fstream 还可以读写图片、音频等二进制文件,需要设置 ios::binary 模式。
  • 文件指针控制:用 tellg() / tellp() 知道当前读写位置,用 seekg() / seekp() 跳到指定位置,实现随机访问。
  • 同时处理多个文件:可以创建多个 ifstreamofstream 对象,同时打开几个文件。

学会了 fstream,你就掌握了 C++ 程序“存下记忆”的本领。以后做密码本、记分板、学生成绩管理系统、记账软件……都会用到它。它像 cincout 一样友好,只要记住“打开→读写→关闭”三步走,再顺手检查一下打开是否成功,你的程序就能和数据安稳做朋友啦!

例题精讲

1单选题

以下关于C++文件读写的说法,哪个是正确的?

Aifstream默认以ios::out模式打开文件
Bofstream默认以ios::in模式打开文件
Cifstream默认以ios::in模式打开文件
Dfstream默认同时以ios::in和ios::out模式打开文件
2判断题

使用ofstream写入文件时,如果文件不存在,系统会自动创建该文件。

3单选题

以下哪个函数用于从文件中读取一行字符串?

Agetline()
Bread()
Cwrite()
Dget()
4填空题
使用fstream对象同时读写文件时,需要在打开文件时指定模式为___
5填空题
打开文件后,通常用___成员函数检查文件是否成功打开。