C++ 从入门到精通C++ 从入门到精通
首页
基础教程
进阶教程
实战项目
编程指南
首页
基础教程
进阶教程
实战项目
编程指南
  • 💪 进阶基础

    • 📚 C++ 进阶教程
    • 第8章 - 指针基础
    • 第9章 - 引用和动态内存
    • 第10章 - 结构体和枚举
    • 第11章 - 文件操作
    • 第12章 - 预处理器和命名空间
  • 🎯 面向对象编程

    • 第13章 - 类和对象基础
    • 第14章 - 构造函数和析构函数
    • 第15章 - 封装、继承、多态
    • 第16章 - 运算符重载
    • 第17章 - 模板基础
    • 第18章 - 异常处理
  • 📦 STL 标准模板库

    • 第19章 - Vector 和 String
    • 第20章 - 容器类
    • 第21章 - Map 和 Set
    • 第22章 - 算法和迭代器

第11章 - 文件操作

嗨,朋友!我是长安。

到目前为止,我们的程序数据都是存储在内存中的,程序关闭后数据就丢失了。

这一章,我们要学习文件操作,让数据能够持久化保存到磁盘文件中!

📁 什么是文件操作?

生活中的例子

  • 写日记 - 把今天发生的事情写到日记本(写文件)
  • 看日记 - 翻开日记本阅读以前的内容(读文件)
  • 续写日记 - 在日记本后面继续写(追加文件)

编程中的文件操作

C++ 使用文件流来操作文件:

类型说明用途
ifstream输入文件流读取文件
ofstream输出文件流写入文件
fstream文件流读写文件

📝 写入文件

基本步骤

  1. 包含头文件 <fstream>
  2. 创建文件流对象
  3. 打开文件
  4. 写入数据
  5. 关闭文件

示例1:写入文本文件

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

int main() {
    // 创建输出文件流对象
    ofstream outFile;
    
    // 打开文件(如果文件不存在会创建)
    outFile.open("data.txt");
    
    // 检查文件是否成功打开
    if (!outFile) {
        cout << "文件打开失败!" << endl;
        return 1;
    }
    
    // 写入数据
    outFile << "Hello, World!" << endl;
    outFile << "这是第二行" << endl;
    outFile << "数字:" << 12345 << endl;
    
    // 关闭文件
    outFile.close();
    
    cout << "数据已写入文件!" << endl;
    
    return 0;
}

示例2:简化写法

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

int main() {
    // 创建时直接打开文件
    ofstream outFile("data.txt");
    
    if (!outFile) {
        cout << "文件打开失败!" << endl;
        return 1;
    }
    
    outFile << "这是简化写法" << endl;
    outFile.close();
    
    return 0;
}

📖 读取文件

示例1:逐行读取

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

int main() {
    ifstream inFile("data.txt");
    
    if (!inFile) {
        cout << "文件打开失败!" << endl;
        return 1;
    }
    
    string line;
    cout << "文件内容:" << endl;
    
    // 逐行读取
    while (getline(inFile, line)) {
        cout << line << endl;
    }
    
    inFile.close();
    
    return 0;
}

示例2:读取单词

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

int main() {
    ifstream inFile("data.txt");
    
    if (!inFile) {
        cout << "文件打开失败!" << endl;
        return 1;
    }
    
    string word;
    cout << "文件内容(按单词):" << endl;
    
    // 逐个单词读取
    while (inFile >> word) {
        cout << word << " ";
    }
    cout << endl;
    
    inFile.close();
    
    return 0;
}

示例3:读取数字

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

int main() {
    // 先写入一些数字
    ofstream outFile("numbers.txt");
    outFile << 10 << " " << 20 << " " << 30 << endl;
    outFile.close();
    
    // 读取数字
    ifstream inFile("numbers.txt");
    int num1, num2, num3;
    
    inFile >> num1 >> num2 >> num3;
    
    cout << "读取的数字:" << num1 << ", " << num2 << ", " << num3 << endl;
    
    inFile.close();
    
    return 0;
}

📋 文件打开模式

模式说明
ios::in读取模式
ios::out写入模式(会覆盖原文件)
ios::app追加模式(在文件末尾添加)
ios::binary二进制模式
ios::trunc清空文件内容

示例:追加内容

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

int main() {
    // 追加模式打开文件
    ofstream outFile("log.txt", ios::app);
    
    if (!outFile) {
        cout << "文件打开失败!" << endl;
        return 1;
    }
    
    outFile << "这是新追加的内容" << endl;
    outFile.close();
    
    cout << "内容已追加!" << endl;
    
    return 0;
}

🌟 实战案例

案例1:学生成绩管理(文件版)

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

struct Student {
    int id;
    string name;
    double score;
};

// 保存学生到文件
void saveStudent(const Student& stu) {
    ofstream outFile("students.txt", ios::app);
    
    if (!outFile) {
        cout << "文件打开失败!" << endl;
        return;
    }
    
    outFile << stu.id << " " << stu.name << " " << stu.score << endl;
    outFile.close();
    
    cout << "学生信息已保存!" << endl;
}

// 显示所有学生
void showAllStudents() {
    ifstream inFile("students.txt");
    
    if (!inFile) {
        cout << "文件不存在或打开失败!" << endl;
        return;
    }
    
    cout << "\n学号\t姓名\t\t成绩" << endl;
    cout << "--------------------------------" << endl;
    
    Student stu;
    while (inFile >> stu.id >> stu.name >> stu.score) {
        cout << stu.id << "\t" << stu.name << "\t\t" << stu.score << endl;
    }
    
    inFile.close();
}

int main() {
    int choice;
    
    do {
        cout << "\n===== 学生管理系统 =====" << endl;
        cout << "1. 添加学生" << endl;
        cout << "2. 显示所有学生" << endl;
        cout << "0. 退出" << endl;
        cout << "请选择:";
        cin >> choice;
        
        if (choice == 1) {
            Student stu;
            cout << "请输入学号:";
            cin >> stu.id;
            cout << "请输入姓名:";
            cin >> stu.name;
            cout << "请输入成绩:";
            cin >> stu.score;
            
            saveStudent(stu);
            
        } else if (choice == 2) {
            showAllStudents();
        }
        
    } while (choice != 0);
    
    cout << "再见!" << endl;
    
    return 0;
}

案例2:配置文件读写

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

struct Config {
    string username;
    string language;
    int fontSize;
};

// 保存配置
void saveConfig(const Config& config) {
    ofstream outFile("config.ini");
    
    outFile << "username=" << config.username << endl;
    outFile << "language=" << config.language << endl;
    outFile << "fontSize=" << config.fontSize << endl;
    
    outFile.close();
    cout << "配置已保存!" << endl;
}

// 加载配置
Config loadConfig() {
    Config config;
    ifstream inFile("config.ini");
    
    if (!inFile) {
        cout << "配置文件不存在,使用默认配置" << endl;
        config = {"guest", "zh-CN", 14};
        return config;
    }
    
    string line;
    while (getline(inFile, line)) {
        size_t pos = line.find('=');
        if (pos != string::npos) {
            string key = line.substr(0, pos);
            string value = line.substr(pos + 1);
            
            if (key == "username") {
                config.username = value;
            } else if (key == "language") {
                config.language = value;
            } else if (key == "fontSize") {
                config.fontSize = stoi(value);
            }
        }
    }
    
    inFile.close();
    return config;
}

int main() {
    // 加载配置
    Config config = loadConfig();
    
    cout << "当前配置:" << endl;
    cout << "用户名:" << config.username << endl;
    cout << "语言:" << config.language << endl;
    cout << "字体大小:" << config.fontSize << endl;
    
    // 修改配置
    cout << "\n请输入新的用户名:";
    cin >> config.username;
    
    // 保存配置
    saveConfig(config);
    
    return 0;
}

案例3:日志记录

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

void writeLog(const string& message) {
    ofstream logFile("app.log", ios::app);
    
    if (!logFile) {
        cout << "日志文件打开失败!" << endl;
        return;
    }
    
    // 获取当前时间
    time_t now = time(0);
    char* dt = ctime(&now);
    string timeStr(dt);
    timeStr.pop_back();  // 移除换行符
    
    // 写入日志
    logFile << "[" << timeStr << "] " << message << endl;
    logFile.close();
}

int main() {
    writeLog("程序启动");
    
    cout << "执行某些操作..." << endl;
    writeLog("用户登录成功");
    
    cout << "继续操作..." << endl;
    writeLog("数据保存成功");
    
    writeLog("程序退出");
    
    cout << "日志已记录到 app.log" << endl;
    
    return 0;
}

案例4:文件复制

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

bool copyFile(const string& source, const string& dest) {
    ifstream inFile(source, ios::binary);
    if (!inFile) {
        cout << "源文件打开失败!" << endl;
        return false;
    }
    
    ofstream outFile(dest, ios::binary);
    if (!outFile) {
        cout << "目标文件创建失败!" << endl;
        inFile.close();
        return false;
    }
    
    // 复制内容
    char ch;
    while (inFile.get(ch)) {
        outFile.put(ch);
    }
    
    inFile.close();
    outFile.close();
    
    return true;
}

int main() {
    string source, dest;
    
    cout << "请输入源文件名:";
    cin >> source;
    
    cout << "请输入目标文件名:";
    cin >> dest;
    
    if (copyFile(source, dest)) {
        cout << "文件复制成功!" << endl;
    } else {
        cout << "文件复制失败!" << endl;
    }
    
    return 0;
}

案例5:统计文件信息

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

void analyzeFile(const string& filename) {
    ifstream inFile(filename);
    
    if (!inFile) {
        cout << "文件打开失败!" << endl;
        return;
    }
    
    int lineCount = 0;
    int wordCount = 0;
    int charCount = 0;
    
    string line, word;
    
    while (getline(inFile, line)) {
        lineCount++;
        charCount += line.length();
        
        // 统计单词数
        for (char ch : line) {
            if (ch == ' ' || ch == '\t' || ch == '\n') {
                if (!word.empty()) {
                    wordCount++;
                    word.clear();
                }
            } else {
                word += ch;
            }
        }
        if (!word.empty()) {
            wordCount++;
            word.clear();
        }
    }
    
    inFile.close();
    
    cout << "\n===== 文件统计 =====" << endl;
    cout << "行数:" << lineCount << endl;
    cout << "单词数:" << wordCount << endl;
    cout << "字符数:" << charCount << endl;
}

int main() {
    string filename;
    
    cout << "请输入文件名:";
    cin >> filename;
    
    analyzeFile(filename);
    
    return 0;
}

🎯 小结

操作类示例
写文件ofstreamofstream out("file.txt");
读文件ifstreamifstream in("file.txt");
读写文件fstreamfstream file("file.txt");
追加内容ios::appofstream out("file.txt", ios::app);
检查打开!fileif (!file) { ... }
关闭文件close()file.close();

重要提醒:

  • ✅ 使用完文件后要关闭
  • ✅ 操作前检查文件是否成功打开
  • ✅ 写入模式会覆盖原文件,追加模式不会
  • ✅ 二进制模式用于非文本文件

💪 练习题

  1. 写一个程序,将用户输入的多行文本保存到文件
  2. 写一个程序,统计文本文件中某个单词出现的次数
  3. 写一个程序,读取文件中的学生成绩,计算平均分并保存到新文件
  4. 实现一个简单的记事本程序(新建、打开、保存、追加)
  5. 写一个程序,合并两个文本文件的内容到第三个文件
点击查看参考答案

题目1 参考答案:

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

int main() {
    ofstream outFile("notes.txt");
    
    if (!outFile) {
        cout << "文件打开失败!" << endl;
        return 1;
    }
    
    cout << "请输入内容(输入 END 结束):" << endl;
    
    string line;
    while (true) {
        getline(cin, line);
        if (line == "END") {
            break;
        }
        outFile << line << endl;
    }
    
    outFile.close();
    cout << "内容已保存到 notes.txt" << endl;
    
    return 0;
}

题目5 参考答案:

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

bool mergeFiles(const string& file1, const string& file2, const string& output) {
    ofstream outFile(output);
    if (!outFile) return false;
    
    // 复制第一个文件
    ifstream in1(file1);
    if (in1) {
        string line;
        while (getline(in1, line)) {
            outFile << line << endl;
        }
        in1.close();
    }
    
    // 复制第二个文件
    ifstream in2(file2);
    if (in2) {
        string line;
        while (getline(in2, line)) {
            outFile << line << endl;
        }
        in2.close();
    }
    
    outFile.close();
    return true;
}

int main() {
    if (mergeFiles("file1.txt", "file2.txt", "merged.txt")) {
        cout << "文件合并成功!" << endl;
    }
    
    return 0;
}

🚀 下一步

恭喜你掌握了文件操作!现在你的程序可以实现数据持久化了!

下一章,我们要学习预处理器和命名空间,了解 C++ 编译的幕后机制!

➡️ 第12章 - 预处理器和命名空间

最近更新: 2025/12/26 17:25
Contributors: 王长安
Prev
第10章 - 结构体和枚举
Next
第12章 - 预处理器和命名空间