第11章 - 文件操作
嗨,朋友!我是长安。
到目前为止,我们的程序数据都是存储在内存中的,程序关闭后数据就丢失了。
这一章,我们要学习文件操作,让数据能够持久化保存到磁盘文件中!
📁 什么是文件操作?
生活中的例子
- 写日记 - 把今天发生的事情写到日记本(写文件)
- 看日记 - 翻开日记本阅读以前的内容(读文件)
- 续写日记 - 在日记本后面继续写(追加文件)
编程中的文件操作
C++ 使用文件流来操作文件:
| 类型 | 说明 | 用途 |
|---|---|---|
ifstream | 输入文件流 | 读取文件 |
ofstream | 输出文件流 | 写入文件 |
fstream | 文件流 | 读写文件 |
📝 写入文件
基本步骤
- 包含头文件
<fstream> - 创建文件流对象
- 打开文件
- 写入数据
- 关闭文件
示例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;
}
🎯 小结
| 操作 | 类 | 示例 |
|---|---|---|
| 写文件 | ofstream | ofstream out("file.txt"); |
| 读文件 | ifstream | ifstream in("file.txt"); |
| 读写文件 | fstream | fstream file("file.txt"); |
| 追加内容 | ios::app | ofstream out("file.txt", ios::app); |
| 检查打开 | !file | if (!file) { ... } |
| 关闭文件 | close() | file.close(); |
重要提醒:
- ✅ 使用完文件后要关闭
- ✅ 操作前检查文件是否成功打开
- ✅ 写入模式会覆盖原文件,追加模式不会
- ✅ 二进制模式用于非文本文件
💪 练习题
- 写一个程序,将用户输入的多行文本保存到文件
- 写一个程序,统计文本文件中某个单词出现的次数
- 写一个程序,读取文件中的学生成绩,计算平均分并保存到新文件
- 实现一个简单的记事本程序(新建、打开、保存、追加)
- 写一个程序,合并两个文本文件的内容到第三个文件
点击查看参考答案
题目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++ 编译的幕后机制!
