IO
- C++中数据输入/输出操作是通过I/O流库实现 
- 流:数据之间的传输操作 - 输出流:数据从内存中传送到某个载体、设备中
- 输入流:数据从某个载体、设备传送到内存缓冲区
 
- C++中流类型 - 标准流I/O流:内存与标准输入、输出设备之间信息传递
- 文件I/O流:内存与外部文件之间信息传递
- 字符串I/O流:内存变量与表示字符串流的字符数组 之间信息传递
 
<ios>
class ios
ios:流基类
- 所有流的父类
- 保存流状态、处理错误
方法
- .fail():判断流是否失效- 尝试超出文件的结尾读取数据时
- 输入流中字符串无法被正确解析
 
- .eof():判断流是否处于文件末尾- 基于C++流库语义,.eof方法只用在.fail调用之后, 用于判断错故障是否是由于到达文件结尾引起的
 
- 基于C++流库语义,
- .clear():重置与流相关状态位- 故障发生后,任何时候重新使用新流都必须调用此函数
 
- if(stream):判断流是否有效- 大部分情况下等同于if(!stream.fial())
 
- 大部分情况下等同于
- .open(filename):尝试打开文件filename并附加到流中- 流方向由流类型决定:输入流对于输入打开、输出流对于 输出打开
- 可以调用.fail判断方法是否失败
 
- .close():关闭依附于流的文件
.[un]setf
| 1 | UKNOWN setf(setflag, unsetfield); | 
- 用途 - .setf:设置某个流操纵符
- .unsetf():取消某个流操纵符
 
- 参数 - setflag:需要设置的操纵符
- unsetflag:取消设置的操纵符
- unsetfield:需要清空的格式设置位组合
 
- 不能像
<<、>>中省略操纵符ios::前缀
.rdbuf
| 1 | template <class Elem, class Traits> | 
- 用途:获得输入、输出流对象中指向缓冲区类streambuf指针- >>、- <<操作符对其有重载,可以方便读取、写入
 
class istream
istream:输入流基类
- 将流缓冲区中数据作格式化、非格式化之间的转换
- 输入
方法
- .unget():复制流的内部指针,以便最后读取的字符能再次 被下个- get函数读取
.get
| 1 | int_type get(); | 
- 用途:从输入流中获取字符、字符串 
- 参数 - delim:分隔符,缺省- \n
- n:
 
(友元)函数
getline
| 1 | template<class E, class T, class A> | 
- 用途:从流 - is读取以- delim为界,到字符串中- 保留开头空白字符、丢弃行尾分割符
- 读取字符直到分隔符,若首字符为分隔符则返回空字符串
 
- 参数 - delim:分隔符,缺省为换行符- \n
 
class ostream
ostream:输出流基类
- 将流缓冲区中数据作格式化、非格式化之间的转换,输出
方法
- .put(ch):将字符- ch写入输出流
class iostream
iosstream:多目的输入、输出流基类
Operator
Insertion Operator
<<:插入操作符,将数据插入流中
- 左操作数是输出流 
- 右操作数是需要插入流中的数据 - 基本类型: - <<会将其自动转换为字符串形式- 整形:默认10进制格式
- [unsigned ]char类型:总是插入单个字符
 
- streambuf类型指针:插入缓冲区对象中所有字符
 
Extraction Operator
>>:提取操作符,从输入流中读取格式化数据
- 左操作数为输入流 
- 右操作数存储从输入流中读取的数据 - 缺省 - skipws:忽略开头所有空白字符
- 空白字符分隔:读取字符直到遇到空白字符
 
- streambuf类型指针:把输入流对象中所有字符写入该 缓冲区
 
- 几乎不提供任何支持检测用户输入是否有效的功能
- 数据格式由变量类型控制
缓冲
缓冲类型
- ISO C要求
- 当且仅当不涉及交互设备时,标准输入、输出全缓存
- 标准错误绝不是全缓存
- 无缓冲:不缓冲字符 - 适用情况:标准错误 
- 标准库不缓冲不意味着系统、设备驱动不缓冲 
 
- 行缓冲:在输入、输出遇到换行符时才会执行I/O操作 - 适用情况:涉及交互设备,如标准输入、输出
 
- 全缓冲:I/O操作只会在缓冲区填满后才会进行 - 适用情况:大部分情况,如驻留在磁盘的文件 
- flush描述I/O缓冲写操作 - 标准I/O函数自动flush
- 手动调用对流调用死fflush函数
 
 
- 缓冲区一般是在第一次对流进行I/O操作时,由标准I/O函数调用
malloc函数分配得到
文件自定义缓冲区
- 文件必须已打开、未做任何操作
setbuf
| 1 | void setbuf(FILE * restrict fp, char * restrict buf); | 
- 用途:打开或关闭缓冲区- 打开:buf必须为大小为BUFSIZ的缓存- BUFSIZ:定义在- stdio.h中,至少256
 
- 关闭:将buf设置为NULL
 
- 打开:
setvbuf
| 1 | int setvbuf(FILE * restrict fp, char * restrict buf, | 
- 用途:设置缓冲区类型
流自定义缓冲区
setbuf
| 1 | virtual basic_streambuf * setbuf(E *s, streamsize n); | 
Manipulator
(流)操纵符:控制格式化输出的一种特定类型值
输出
- 短暂的:只影响下个插入流中的数据
持久的:直到被明确改变为止
双操纵符条目中,前者为默认
setw、setprecision、setfill还需要包含<iomanip>
组合格式
- adjustfield:对齐格式位组合
- basefield:进制位组合
- floatfield:浮点表示方式位组合
位置
- endl:将行结束序列插入输出流,确保输出字符被写入目的流
- setw(n):短暂的
- setfill(ch):持久的,指定填充字符,缺省空格
- left:持久的,指定有效值靠左
- right:持久的,指定有效值靠右
- internal:持久的,指定填充字符位于符号、数值间
数值
- showbase:为整数添加表示其进制的前缀
- fixed:持久的,完整输出浮点数
- scientific:持久的,科学计数法输出浮点数
- setprecision(digits):持久的,精度设置依赖于其他设置- fixed/- scientific:指定小数点后数字位数
- 其他:有效数字位数
 
- hex:持久的,16进制输出无符号整形
- oct:持久的,8进制输出无符号整形
- dec:持久的,10进制输出整形
- noshowpoint/- showpoint:持久的,否/是强制要求包含 小数点
- noshowpos/- showpos:持久的,要求正数前没有/有- +
- nouppercase/- uppercase:持久的,控制作为数据转换部分 产生任意字符小/大写,如:科学计数法中的- e
- noboolalpha/- boolalpha:持久的,控制布尔值以数字/ 字符形式输出
控制
- unitbuf:插入、提取操作之后清空缓冲
- stdio:每次输出后清空stdout、stderr
输入
- skipws/- noskipws:持久的,读取之前是/否忽略空白字符
- ws:从输入流中读取空白字符,直到不属于空白字符为止
<iostream>
- ifstream_withassign:标准输入流类- cin:标准文件stdin
 
- ofstream_withassign:标准输出、错误、log流- cout:标准文件stdout
- cerr:标准文件stderr
- clog:标准文件stderr
 
<fstream>
- ifstream:文件输入流类- 默认操作:ios::in
 
- 默认操作:
- ofstream:文件输出流类- 默认操作:ios::out|ios::trunc
 
- 默认操作:
- fstream:文件流输入、输出类
例
| 1 | 
 | 
流操作复制文件
- 逐字符复制 - 1 
 2
 3
 4
 5
 6
 7
 std::ifstream input("in", ios::binary);
 std::ofstream output("out", ios::binary);
 char ch;
 while(input.get(ch)){
 output << ch;
 }- 使用input >> ch默认会跳过空白符,需要使用input.unsetf(ios::skipws)取消
 
- 使用
- 逐行复制 - 1 
 2
 3
 4
 5
 std::string line;
 while(getline(input, line)){
 output << line << "\n";
 }- 若文件最后没有换行符,则复制文件会末尾多\n
 
- 若文件最后没有换行符,则复制文件会末尾多
- 迭代器复制 - 1 
 2
 3
 4
 5
 6
 input.unsetf(ios::skipws);
 copy(istream_iterator(input), istream_iterator(),
 ostream_iterator(output, "")
 );
- 缓冲区复制 - 1 - output << input.rdbuf(); - 丢失\n
 
- 丢失
标准输出文件内容
- <<操作符- 1 
 2
 3
 4
 5
 ifstream input("in");
 cout << input.rdbuf();
- .get方法- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10- while(input.get(*cout.rdbuf()).eof()){ 
 // 读取一行
 if(input.fail()){
 // `get`遇到空行无法提取字符,会设置失败标志
 input.clear();
 // 清除错误标志
 }
 cout << char(input.get());
 // 提取换行符,转换为`char`类型输出
 }
- .get方法2- 1 - input.get(*cout.rdbuf(), EOF); 
<sstream>
- 基于C类型字符串 - char *编写- istrstream:串输入流类
- ostrstream:串输出流类
- strstream:串输入、输出流类
 
- 基于 - std::string编写:推荐- istringstream:串输入流类
- ostringstream:串输出流类
- stringstream:串输入、输出流类
 
例
| 1 | 
 |