核心要点速览
- 3 类流:
ifstream(读)、ofstream(写)、fstream(读写),继承自istream/ostream/iostream,复用>>/<<。 - 5 种模式:
in(读)、out(写 + 截断)、app(追加)、ate(尾定位)、binary(二进制),支持|组合。 - 4 步流程:打开→检查(
is_open())→读写→关闭(close()),关键在 "检查" 和 "关闭"。 - 4 个状态函数:
eof()(文件尾)、fail()(可恢复错)、bad()(严重错)、good()(无错)。 - 补充:
appvsate、文本 vs 二进制、getline()与>>混用、二进制字节对齐、string禁忌。
一、文件流类
| 类名 | 功能 | 默认模式 | 核心方法 | 易错 | |
|---|---|---|---|---|---|
ifstream |
仅读文件 | ios::in |
>>、getline() |
打开不存在的文件会失败(ofstream会自动创建) |
|
ofstream |
仅写文件 | ios::out(含trunc) |
<<、put() |
默认清空文件,追加需显式加ios::app |
|
fstream |
读写文件 | 无(需显式指定) | 兼具前两者方法 | 1. 必须加 ios::in或ios::out 才支持读写;2. 打开不存在的文件不会自动创建 |
二、打开模式
| 模式 | 作用 | 补充 |
|---|---|---|
ios::in |
读权限,文件不存在则失败 | fstream需显式加,ifstream默认包含 |
ios::out |
写权限,默认截断 | 与ios::in组合时,文件不存在会失败 |
ios::app |
仅尾追加,指针固定 | 必须搭配ios::out,seekp()移动无效 |
ios::ate |
打开后指针到尾,可移动 | 支持随机读写,区别于app的核心是 "指针可动" |
ios::binary |
禁用换行转换 | 读写结构体 / 图片必须显式指定,否则数据失真 |
三、操作流程
-
打开 :
ifstream ifs("a.txt");或fs.open("b.txt", ios::in|ios::out); -
检查 :
if (!ifs.is_open()) { /* 处理失败 */ }避免路径错误 / 权限不足导致后续崩溃,必写步骤。
-
读写:
-
文本模式(解决
getline()与>>混用问题):- 用
>>读取数据:ifs >> val;(按空白分割,读取后缓冲区残留换行符\n) - 关键处理:
ifs.ignore(1024, '\n');(清空缓冲区残留的\n,避免后续getline()读空行) - 读整行数据:
getline(ifs, str);(保留空格,正常读取整行)
- 用
-
二进制模式(解决字节对齐和
string禁忌问题):- 关闭字节对齐:
#pragma pack(1)(跨平台必备,强制结构体成员连续存储) - 定义结构体:
struct Student { int id; char name[20]; };(禁用string,用固定长度char数组) - 恢复默认对齐:
#pragma pack() - 二进制写入:
ofs.write(reinterpret_cast<char*>(&s), sizeof(s));(必须强转为char*类型)
- 关闭字节对齐:
-
-
关闭 :
ifs.close();刷新缓冲区(防数据丢失)、释放资源,必写步骤。
易错
getline()与>>混用:>>残留\n导致空行,用ignore(1024, '\n')清空。- 二进制字节对齐:不同编译器对齐规则不同,用
#pragma pack(1)强制紧凑存储,避免跨平台错位。 string禁忌:二进制读写时,string含指针,写入的是地址,读取崩溃,需用char数组。
四、状态判断函数
| 函数 | 含义 | 典型场景 | 恢复 / 处理 |
|---|---|---|---|
eof() |
到达文件尾 | 读循环结束判断 | 正常状态,无需处理 |
fail() |
可恢复错误(格式错等) | >>读整数遇字母 |
恢复:clear()(清错误)+ ignore(1024, '\n')(清缓冲区) |
bad() |
严重错误(文件损坏) | 磁盘故障 | 不可恢复,终止程序 |
good() |
操作无错 | 读写正常完成 | 等价于!eof() && !fail() && !bad() |
五、补充
1. ios::app和ios::ate的区别?
app:仅尾追加,写指针固定,不可移动,只能写;ate:初始指针在尾,可通过seekg()/seekp()移动,支持随机读写。
2. 文本与二进制文件操作的区别?
- 文本:
>>/<</getline(),自动转换换行符(\n→\r\n),人类可读; - 二进制:
read()/write()+ios::binary,无转换,原始字节流,效率高,需处理字节对齐。
3. 为什么二进制读写结构体要处理字节对齐?
- 编译器为提高内存访问效率,会自动对齐结构体成员,导致不同编译器下结构体字节数不一致;
- 跨平台读取时数据错位,用
#pragma pack(1)强制紧凑对齐解决。
4. 不调用close()有什么后果?
- 缓冲区数据未写入磁盘,程序崩溃可能导致数据丢失;
- 文件资源被占用,其他程序无法访问;
- 流对象不可复用。
5. fail()和bad()的区别?
fail():可恢复(格式错、模式错),用clear()+ignore()恢复;bad():严重错误(磁盘损坏、文件被删),不可恢复。