输入输出与文件操作

输入输出与文件操作
flowwalker输入输出与文件操作
目录
[TOC]
比较重要的内容
1 | int x; |
可见istream在其基类内重载了operator bool
1 |
|
getline
istream & getline(char* buf,int bufsize,char delim);
delim缺省,默认为\n,从输入流中读取(bufsize-1)个字符到缓冲区,或读到delim
- delim不会读入缓冲区,但会被输入流取走
- 达到或超出bufsize报错
1 | // ■ getline读入字符个数超过了bufSize个 |
1 | // ■ 可以用 if(!cin.getline(...)) 判断输入是否结束 |
1 | // 现代 |
istream 类的成员函数
bool eof();— 判断输入流是否结束int peek();— 返回下一个字符,但不从流中去掉istream & putback(char c);— 将字符c放回输入流istream & ignore(int nCount = 1, int delim = EOF);— 从流中删掉最多nCount个字符,遇到EOF时结束getline 读到留在流中的
'\n'就会返回
1
2
3
4
5
6
7
8
9
10
11
using namespace std;
int main() {
int x;
char buf[100];
cin >> x;
cin.getline(buf, 90);
cout << buf << endl;
return 0;
}输入:
1 12 abcd输出:
1 abcd(前面有一个空格,因为
>>留下的空格还在流里)输入:
1 12程序立即结束,无输出。(
getline直接读到了12后面的'\n')istream 类的成员函数
bool eof();— 判断输入流是否结束int peek();— 返回下一个字符,但不从流中去掉istream & putback(char c);— 将字符c放回输入流istream & ignore(int nCount = 1, int delim = EOF);— 从流中删掉最多nCount个字符,遇到EOF时结束getline 读到留在流中的
'\n'就会返回
1
2
3
4
5
6
7
8
9
10
11
using namespace std;
int main() {
int x;
char buf[100];
cin >> x;
cin.getline(buf, 90);
cout << buf << endl;
return 0;
}输入:
1 12 abcd输出:
1 abcd(前面有一个空格,因为
>>留下的空格还在流里)输入:
1 12程序立即结束,无输出。(
getline直接读到了12后面的'\n')
cin.width(): 最大读取n-1个字符
cout默认右对齐
设置宽度是一次性的
流操纵器:
cout << tab不是把tab的"返回值"传给cout,而是把tab这个"函数本身"传给cout,让cout内部再调用它。ostream& tab(ostream& output) { return output << '\t'; } //重载内部等价于return (*p)(*this); // 也就是 tab(cout) ostream& operator<<(ostream& (*p)(ostream&)); // ^^^^^^^^^^^^^^^^^ // 函数指针:接受ostream&,返回ostream& <!--code13-->
一、C++ IO流类体系(基础核心)
1. 流类继承关系(根类:ios)
1 | graph TD |
2. 标准流对象核心说明
| 对象 | 绑定设备 | 缓冲机制 | 核心用途 | 能否重定向 |
|---|---|---|---|---|
| cin | 标准输入(键盘) | 有缓冲 | 常规数据输入 | 可重定向到文件读取 |
| cout | 标准输出(屏幕) | 有缓冲 | 常规数据输出 | 可重定向到文件写入 |
| cerr | 标准错误输出 | 无缓冲 | 紧急错误信息(程序崩溃也能正常输出) | 不可重定向 |
| clog | 标准错误输出 | 有缓冲 | 非紧急运行日志(减少IO次数,性能更高) | 不可重定向 |
二、标准IO核心操作
1. 输入/输出重定向
核心函数:freopen(头文件<iostream>)
| 用法 | 核心功能 |
|---|---|
freopen("文件名", "r", stdin); | 将标准输入cin重定向到指定文件,从文件读取数据 |
freopen("文件名", "w", stdout); | 将标准输出cout重定向到指定文件,向文件写入数据 |
最简示例
1 | // 输入重定向:从in.txt读取数据 |
2. 输入流结束判断
标准写法:while(cin >> x)
- 底层原理:
>>运算符返回istream对象,istream类重载了operator bool,流无效/结束时返回false - 结束触发条件:
- 键盘输入:单独一行输入Ctrl+Z,标记输入流结束
- 文件输入:读取到文件末尾(EOF),流自动标记为结束
- 扩展:可通过重载
operator>>和operator bool实现自定义流的结束判断
1. 变量引用的本质
- 地址传递:
int &n传入的是内存地址。函数获得了修改n1、n2的权限,但并不具备预知未来输入内容的能力。- 初始值陷阱:在执行
cin >> n这一行指令之前,n指向的内存空间里存放的是旧数据(上一次循环留下的值或随机值)。2. 旧版逻辑失效原因:时序错位
C++
1
2 >if(n != -1) // 步骤 A:判断旧数据
cin >> n; // 步骤 B:覆盖新数据
- 逻辑断层:当输入
-1时,由于步骤 A 使用的是旧值(非-1),程序会执行步骤 B 将-1读入内存。但此时判断已经结束,else分支里的stop = true无法被触发。- 滞后效应:
stop标志位的更新比输入流的变化慢了一个周期。3. 链式调用的“惯性”与“熔断”
在
while(m >> n1 >> n2)执行时:
- 惯性读取:读入
n1 = -1后,因为stop仍为false,程序会顺着指令链继续执行m >> n2。- 输出溢出:当这一轮
while条件执行完毕时,n1和n2都已被新值覆盖,随后被cout打印,导致输出了本该拦截的-1和随后的数字。4. 正确的逻辑构造:先做后看
严谨的实现必须确保:修改动作发生在状态判定之前。
- 逻辑顺序:
- 检查熔断:
if(stop) return *this;(若前一步已停止,立即拦截)。- 执行修改:
cin >> n;(更新内存中的值)。- 同步状态:
if(n == -1) stop = true;(根据刚读入的值更新标志)。
3. istream核心成员函数(高频考点)
(1)getline:按行读取字符串
函数原型
1 | // 读到换行符\n停止 |
核心规则
- 最多读取
bufSize-1个字符,自动在缓冲区末尾添加字符串结束符’\0’ - 分隔符
\n/delim会从流中移除,但不会存入缓冲区 - 若读取字符数超过bufSize,会置位流的
failbit,后续所有读操作全部失效
错误判断:if(!cin.getline(...)) → 读取失败/流结束时返回true
(2)其他常用成员函数
| 函数 | 核心功能 |
|---|---|
bool eof(); | 判断输入流是否到达文件末尾(EOF) |
int peek(); | 返回流中下一个字符,不从流中移除(仅“偷窥”) |
istream& putback(char c); | 将字符c放回输入流的开头 |
istream& ignore(int n=1, int delim=EOF); | 跳过流中最多n个字符,遇到delim提前停止 |
(3)getline高频坑点
cin >> x 读取完成后,会在流中残留换行符\n,后续调用getline会直接读取空行,需先用ignore()清除残留换行。
三、流操纵算子(格式化输入输出)
必须包含头文件:
<iomanip>
1. 整数基数控制
| 算子 | 功能 |
|---|---|
| dec | 十进制输出(默认格式) |
| oct | 八进制输出 |
| hex | 十六进制输出 |
| setbase(n) | 指定输出基数(仅支持8/10/16) |
2. 浮点数精度控制(核心考点)
核心工具
- 成员函数:
cout.precision(n); - 流操纵算子:
cout << setprecision(n); - 两者功能完全一致,算子支持链式连续输出
精度含义规则(与输出格式强绑定)
| 输出格式 | 控制算子 | setprecision(n)的含义 |
|---|---|---|
| 默认格式(defaultfloat) | 无/resetiosflags | n = 总有效数字位数 |
| 定点格式(fixed) | setiosflags(ios::fixed) / fixed | n = 小数点后保留位数 |
| 科学计数格式(scientific) | setiosflags(ios::scientific) / scientific | n = 小数点后保留位数 |
核心规则
- 小数截短显示时,自动执行四舍五入
- 格式取消:
resetiosflags(ios::fixed/ios::scientific)
3. 域宽设置(setw / width)
核心用法
- 成员函数:
cin.width(n);/cout.width(n); - 流操纵算子:
cin >> setw(n);/cout << setw(n);
核心规则
- 域宽设置仅对下一次读写操作有效,每次读写前必须重新设置
- 输入时:最多读取
n-1个字符(预留\0的存储位置) - 无参
width():返回当前的域宽值
4. 用户自定义流操纵算子
定义规则
返回值和参数均为ostream&的函数,示例:
1 | // 自定义制表符算子 |
底层原理
ostream重载了<<运算符,支持接收函数指针,会自动调用传入的函数,并将流对象本身作为参数传入。
四、文件IO操作(核心应用)
必须包含头文件:
<fstream>
1. 文件打开与关闭
(1)两种打开方式
| 方式 | 示例 |
|---|---|
| 构造对象时直接打开 | ofstream outFile("test.txt", ios::out|ios::binary); |
| 先创建对象,再用open打开 | ofstream fout; fout.open("test.txt", ios::out); |
(2)常用打开模式
| 模式 | 核心功能 |
|---|---|
| ios::in | 只读模式打开(ifstream默认模式) |
| ios::out | 只写模式打开,清空原有内容(ofstream默认模式) |
| ios::app | 追加模式,保留原有内容,始终在文件尾部写入 |
| ios::ate | 打开后文件指针定位到尾部,可在文件任意位置写入 |
| ios::binary | 二进制模式打开,不执行换行符自动转换 |
(3)打开成功判断
1 | if(!fout){ // 流对象返回false,代表打开失败 |
(4)文件关闭
文件使用完毕必须显式关闭,释放系统资源:
1 | fin.close(); |
2. 文件读写指针操作
| 指针类型 | 适用流 | 核心函数 | 功能 |
|---|---|---|---|
| 读指针 | ifstream/fstream | tellg() | 获取读指针当前位置(字节数) |
seekg(偏移量, 基准位置) | 移动读指针到指定位置 | ||
| 写指针 | ofstream/fstream | tellp() | 获取写指针当前位置(字节数) |
seekp(偏移量, 基准位置) | 移动写指针到指定位置 |
基准位置参数
ios::beg:文件开头(默认基准)ios::cur:指针当前位置ios::end:文件尾部- 偏移量支持负数(代表向前移动)
3. 文本文件读写
- 文本文件流的用法与cin/cout完全一致,所有流操纵算子、>>/<<运算符均适用
- 典型场景:从文本文件读取数据、处理后写入另一个文本文件(如整数排序、文本拷贝)
4. 二进制文件读写(核心考点)
核心函数
| 函数 | 标准用法 |
|---|---|
| write(写) | fout.write((const char*)&变量地址, sizeof(变量类型)); |
| read(读) | fin.read((char*)&变量地址, sizeof(变量类型)); |
辅助函数
gcount():返回最近一次read操作实际读取的字节数
核心特性
- 直接读写内存中的二进制数据,无格式转换,记事本打开为乱码
- 适用于结构体/类对象的批量读写,效率高、无精度损失
- 必须配合
ios::binary模式打开文件
5. 文本文件 vs 二进制文件(高频考点)
换行符系统差异
| 系统 | 换行符 | ASCII码 |
|---|---|---|
| Linux/Unix | \n | 0x0a |
| Windows | \r\n | 0x0d 0x0a |
| Mac OS | \r | 0x0d |
打开模式差异
| 系统 | 文本模式(无ios::binary) | 二进制模式(ios::binary) |
|---|---|---|
| Linux/Unix | 无任何转换,与二进制模式无区别 | 无任何转换,按原始字节读写 |
| Windows | 读:自动将\r\n转为\n(少读1字节)写:自动将 \n转为\r\n(多写1字节) | 无任何转换,按原始字节读写 |
五、注意点
- getline坑点:
cin >>后残留的\n会导致getline直接读取空行,需用cin.ignore()清除换行符 - setw单次有效:域宽设置仅对下一次读写生效,每次使用前必须重新设置
- 流failbit置位:getline读取溢出、读取出错会置位failbit,后续所有流操作全部失效,需用
cin.clear()重置流状态 - Windows换行转换:二进制读写必须添加
ios::binary,否则会因换行符自动转换导致文件读写异常 - 文件关闭要求:文件打开使用后必须显式调用
close(),否则会导致资源泄漏,其他程序无法操作该文件 - cerr不可重定向:错误信息必须用cerr输出,避免cout重定向后,错误信息无法在屏幕显示
- 二进制读写强制转换:write/read的第一个参数必须强制转为
char*/const char*,否则会编译报错










