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:分隔符,缺省\nn:
(友元)函数
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:持久的,控制作为数据转换部分 产生任意字符小/大写,如:科学计数法中的enoboolalpha/boolalpha:持久的,控制布尔值以数字/ 字符形式输出
控制
unitbuf:插入、提取操作之后清空缓冲stdio:每次输出后清空stdout、stderr
输入
skipws/noskipws:持久的,读取之前是/否忽略空白字符ws:从输入流中读取空白字符,直到不属于空白字符为止
<iostream>
ifstream_withassign:标准输入流类cin:标准文件stdin
ofstream_withassign:标准输出、错误、log流cout:标准文件stdoutcerr:标准文件stderrclog:标准文件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
10while(input.get(*cout.rdbuf()).eof()){
// 读取一行
if(input.fail()){
// `get`遇到空行无法提取字符,会设置失败标志
input.clear();
// 清除错误标志
}
cout << char(input.get());
// 提取换行符,转换为`char`类型输出
}.get方法21
input.get(*cout.rdbuf(), EOF);
<sstream>
基于C类型字符串
char *编写istrstream:串输入流类ostrstream:串输出流类strstream:串输入、输出流类
基于
std::string编写:推荐istringstream:串输入流类ostringstream:串输出流类stringstream:串输入、输出流类
例
1 |
|

