cpp自学 day20(文件操作)
基本概念
程序运行时产生的数据都属于临时数据,程序一旦运行结束都会被释放
通过文件可以将数据持久化
C++中对文件操作需要包含头文件 <fstream>
文件类型分为两种:
- 文本文件 - 文件以文本的ASCII码形式存储在计算机中
- 二进制文件 - 文件以文本的二进制形式存储在计算机中,用户一般不能直接读懂它们
操作文件的三大类:
1. ofstream:写操作
2. ifstream:读操作
3. fstream:读写操作
#include <fstream> // 必须包含的头文件
数据特性 | 说明 |
---|---|
程序运行时数据 | 临时数据,程序结束即释放 |
文件持久化数据 | 长期存储在磁盘中 |
文件打开模式
模式标志 | 功能描述 |
---|---|
ios::in | 为读取打开文件 |
ios::out | 为写入打开文件 |
ios::ate | 初始定位到文件末尾 |
ios::app | 追加写入模式 |
ios::trunc | 存在则清空重建 |
ios::binary | 二进制模式操作 |
文本文件
写文件
void test01() {
// 1. 包含头文件(已在全局包含)
// 2. 创建输出流对象
ofstream ofs;
// 3. 指定打开方式(组合模式用 | 连接)
ofs.open("test.txt", ios::out | ios::trunc);
// 4. 写入格式化数据
ofs << "姓名:张三" << endl; // 正确使用<<运算符
ofs << "性别:男" << endl;
ofs << "年龄:18" << endl;
// 5. 关闭文件流
ofs.close();
}
读文件
基础操作框架
#include <fstream> // 必须包含的头文件
#include <string> // 字符串操作支持
void readFileDemo() {
// 1. 创建流对象
ifstream ifs;
// 2. 打开文件并验证
ifs.open("test.txt", ios::in); // ios::in表示读取模式
if (!ifs.is_open()) { // 必须检查打开状态
cerr << "文件打开失败" << endl;
return;
}
// 3. 读取数据(四种方式见下文)
// 4. 关闭文件流
ifs.close();
}
四种读取方式对比
方式1:运算符重载读取
char buf[1024] = {0}; // 1024为缓冲区长度
while (ifs >> buf) { // 自动处理空格/换行分隔
cout << buf << endl;
}
特点:
- 自动按空白符分割内容
- 缓冲区需预分配固定大小
- 适合结构化数据读取
方式2:getline成员函数
char buf[1024] = {0};
while (ifs.getline(buf, sizeof(buf))) { // 流对象的成员函数
cout << buf << endl; // 自动处理换行符
}
特点:
- 精确控制缓冲区大小
- 自动去除换行符
- 需注意缓冲区溢出风险
方式3:全局getline函数
string buf;
while (getline(ifs, buf)) { // 使用string自动管理内存
cout << buf << endl; // 无长度限制
}
特点:
- 自动管理内存
- 无需担心缓冲区溢出
- 标准推荐方式
方式4:逐字符读取
char c;
while ((c = ifs.get()) != EOF) { // EOF检测
cout << c; // 原样输出所有字符
}
特点:
- 完全控制读取过程
- 适合二进制文件处理
- 性能开销较大
二进制文件
核心操作框架
#include <fstream>
#include <string>
// 示例数据结构
struct PlayerData {
int id; // 4字节
double score; // 8字节
char name[32]; // 32字节
}; // 总大小:44字节
void binaryDemo() {
// 创建流对象
fstream file("game.dat", ios::binary | ios::out | ios::in);
// 验证文件状态
if (!file.is_open()) {
cerr << "文件打开失败" << endl;
return;
}
// 读写操作(见下文示例)
file.close();
}
读写文件
// 读取基本类型
int loadedScore;
file.read(reinterpret_cast<char*>(&loadedScore), sizeof(int));
// 读取结构体(需内存对齐)
#pragma pack(push, 1) // 1字节对齐
struct PackedData {
short type;
bool valid;
// ...
};
#pragma pack(pop)
PackedData data;
file.read(reinterpret_cast<char*>(&data), sizeof(PackedData));
// 批量读取
vector<PlayerData> players(10);
file.read(reinterpret_cast<char*>(players.data()),
players.size() * sizeof(PlayerData));