1、流
流:数据从一个对象到另一个对象的传输
功能:标准输入输出+文件管理
分类 | 含义 |
---|---|
文本流 | 一串ASCII字符 |
二进制流 | 一串二进制 |
2、流类型
标准库定义了三大类流类型:标准I/O流、文件流、字符串流
2.1 标准I/O流
1、ios是抽象类
2、ostream是cout、clog、cerr的类
3、istream是cin的类
2.2 文件流类型
1、ifstream从文件读取数据
2、ofstream向文件写入数据
3、iofstream文件读写数据
2.3 字符串流类型
1、istringstream从string读取数据
2、ostringstream向string写入数据
3、iostringstream读写string数据
3、流对象
通常标准I/O流对象是全局对象不需要定义,而文件流对象和字符串流对象虚需要用户定义
标准I/O流对象有以下四个:
No. | 全局流对象 | 名称 | 缓存 |
---|---|---|---|
1 | cout | 标准输出流 | 带缓存 |
2 | cin | 标准输入流 | 带缓存 |
3 | clog | 标准日志流 | 带缓存 |
4 | cerr | 标准错误流 | 无缓存 |
注意:流对象通常不能复制
4、流对象状态
流对象状态在某一时刻必定处于以下四个状态之一:
No. | 状态 | 含义 |
---|---|---|
1 | good() | 前一个流操作成功 |
2 | eof() | 到输入尾/文件尾 |
3 | fail() | 发生意外的事情(读取失败) |
4 | bad() | 发生意外严重的事情(磁盘读取失败) |
5、I/O操作
I/O操作主要有如下五种:
1、输入操作:in>>x或者getline(in,s)
2、输出操作:out<<x
3、操作符
4、流状态
5、格式化
5.1 输出流默认配置
类型 | 进制 | 宽度 | 对齐 | 填充 | 精度 |
---|---|---|---|---|---|
整数 | 十进制 | 0 | 右对齐 | 空格 | 1 |
实数 | 十进制 | 0 | 右对齐 | 空格 | 6位数 |
字符串 | – | 0 | 右对齐 | 空格 | 字符串实际长度 |
5.2 格式控制
(1)格式控制成员函数
流对象.格式控制函数(实参)
(2)预定义格式控制函数
预定义格式控制函数(实参)
(3)流的输出控制格式
作用 | 格式控制成员函数 | 预定义格式控制函数 | 预定义格式控制符/操作子 | 效果持续 |
---|---|---|---|---|
进制 | flag() setf() unsetf() | setiosflags() | dec oct hex showbase | 能持续 |
宽度 | width() | setw() | 不能持续 | |
对齐 | flags() setf() unsetf() | setioflags() | right left internal | 能持续 |
填充 | fill© | setfill© | 能持续 | |
精度 | precision(n) | setprecision(n) | 能持续 |
流的输出控制格式:dex,oct,hex
数据输入成员函数:
字符输入成员函数:get()
字符串输入成员函数:getline()
数据输出成员函数:put()
5.3 对齐方式
flag | manipulator | 作用 |
---|---|---|
ios::left | left | 居左 |
ios::right | right | 居右 |
ios::internal | internal | 输出符号或进制后填充 |
(1)成员函数方式
#include <iostream>
using namespace std;
int main(){
int n=-11;
cout.width(6);
cout.flags(ios::right);
cout << n << endl;
cout.width(6);
cout.flags(ios::left);
cout << n << endl;
cout.width(6);
cout.flags(ios::internal);
cout << n << endl;
}
输出结果:
-11
-11
- 11
(2)操作子方式
#include <iostream>
#include <iomanip>
using namespace std;
int main(){
int n=-11;
cout << setw(6) << right << n << endl;
cout << setw(6) << left << n << endl;
cout << setw(6) << internal << n << endl;
}
输出结果:
-11
-11
- 11
(3)混合方式
#include <iostream>
using namespace std;
int main(){
int n=-11;
cout.width(6); cout << left << n << endl;
cout.width(6); cout << right << n << endl;
cout.width(6); cout << internal << n << endl;
}
输出结果:
-11
-11
- 11
5.4 整数输出格式
flag | manipulator | 作用 | 是否默认 |
---|---|---|---|
ios::dec | dec | 十进制 | 是 |
ios::oct | oct | 八进制 | 否 |
ios::hex | hex | 十六进制 | 否 |
ios::upperccase | uppercase | 使用大写输出十六进制 | 否 |
ios::showbase | showbase | 输出带有进制的字符 | 否 |
(1)成员函数方式
#include <iostream>
using namespace std;
int main(){
int n=-11;
cout.flags(ios::dec);
cout << n << endl;
cout.flags(ios::hex);
cout << n << endl;
cout.flags(ios::oct);
cout << n << endl;
cout.flags(ios::showbase|ios::dec);
cout << n << endl;
cout.flags(ios::showbase|ios::oct);
cout << n << endl;
cout.flags(ios::showbase|ios::hex);
cout << n << endl;
cout.flags(ios::showbase|ios::uppercase|ios::dec);
cout<<n<<endl;
cout.flags(ios::showbase|ios::uppercase|ios::oct);
cout<<n<<endl;
cout.flags(ios::showbase|ios::uppercase|ios::hex);
cout<<n<<endl;
}
输出结果:
-11
fffffff5
37777777765
-11
037777777765
0xfffffff5
-11
037777777765
0XFFFFFFF5
(2)操作子方式
#include <iostream>
using namespace std;
int main(){
int n=-11;
cout << dec << n << endl;
cout << hex << n << endl;
cout << oct << n << endl;
cout << showbase << dec << n << endl;
cout << oct << n << endl;
cout << hex << n << endl;
cout << uppercase << dec << n << endl;
cout << oct << n << endl;
cout << hex << n << endl;
}
输出结果:
-11
fffffff5
37777777765
-11
037777777765
0xfffffff5
-11
037777777765
0XFFFFFFF5
5.5 浮点数输出格式
flag | 作用 | 是否默认 | 精度 |
---|---|---|---|
ios::defaultfloat | 默认浮点数格式 | 是 | 最多保留多少位数字 |
ios::scientific | 科学技术法输出浮点数 | 否 | 小数点后最多保留多少位数字 |
ios::fixed | 定点数方式输出实数 | 否 | 小数点后最多保留多少位数字 |
如果浮点数没有小数时默认不显示小数点,使用ios::showpoint可以强制输出浮点数时,必须带小数点。
定点数方式比浮点数方式更精确
取浮点数精确度时,设置ios::fixed
(1)成员函数方式
#include <iostream> // cout, std::fixed, std::scientific
using namespace std;
int main () {
double a = 3.1415926534;
double b = 2006.0;
double c = 1.0e-10;
cout.precision(5);
cout << "default:\n";
cout << a << endl << b << endl << c << endl;
cout << "fixed:\n";
cout.flags(ios::fixed);
cout << a << endl << b << endl << c << endl;
cout << "scientific:\n";
cout.flags(ios::scientific);
cout << a << endl << b << endl << c << endl;
return 0;
}
输出结果:
default:
3.1416
2006
1e-10
fixed:
3.14159
2006.00000
0.00000
scientific:
3.14159e+00
2.00600e+03
1.00000e-10
(2)操作子方式
#include <iostream>
#include <iomanip>
using namespace std;
int main(){
double a = 3.1415926534;
double b = 2006.0;
double c = 1.0e-10;
cout<< setprecision(5)
<< "default:\n"
<< a << endl << b << endl << c <<endl;
cout << "fixed:\n"<<fixed
<< a << endl << b << endl << c <<endl;
cout << "scientific:\n"<<scientific
<< a << endl << b << endl << c <<endl;
return 0;
}
输出结果:
default:
3.1416
2006
1e-10
fixed:
3.14159
2006.00000
0.00000
scientific:
3.14159e+00
2.00600e+03
1.00000e-10
(3)混合方式
#include <iostream>
#include <iomanip>
using namespace std;
int main(){
double a = 3.1415926534;
double b = 2006.0;
double c = 1.0e-10;
std::cout.precision(5);
std::cout << "default:\n";
std::cout << a << endl << b << endl << c <<endl << endl;
std::cout<<"fixed:\n" <<std::fixed;
std::cout << a << endl << b << endl <<c <<endl << endl;
std::cout << "scientific:\n" <<std::scientific;
std::cout << a << endl << b << endl << c << endl << endl;
return 0;
}
输出结果:
default:
3.1416
2006
1e-10
fixed:
3.14159
2006.00000
0.00000
scientific:
3.14159e+00
2.00600e+03
1.00000e-10
5.5 布尔类型输出格式
flag | manipulator | 作用 | 默认 |
---|---|---|---|
ios::boolalpha | boolalpha | 把bool值以字符串true/false输出 | 否 |
5.6 其他
flag | manipulator | 作用 | 默认 |
---|---|---|---|
ios::showpos | showpos | 输出十进制0或者正数时,带+号 | 否 |
(1)成员函数方式
#include <iostream>
using namespace std;
int main(){
int p=1;
int z=0;
int n=-1;
cout.setf(ios::showpos);
cout << p << '\t' << z << '\t' << n << endl;
cout.unsetf(ios::showpos);
cout << p << '\t' << z << '\t' << n << endl;
return 0;
}
输出结果:
+1 +0 -1
1 0 -1
(2)操作子方式
#include <iostream>
using namespace std;
int main(){
int p=1;
int z=0;
int n=-1;
cout<<showpos << p << '\t' << z << '\t' << n << endl;
cout<<noshowpos << p << '\t' << z << '\t' << n << endl;
return 0;
}
输出结果:
+1 +0 -1
1 0 -1
复数虚部a+bi使用showpos非常合适
5.7 注意
最新版C++的iostream库中,在使用setiosflags()前要先使用resetiosflags()清除旧有相应信息。
cout << resetiosflags(ios::basefield)<< setiosflags(ios::hex) << 10 << endl;
以下三类格式化在使用setiosflags(),要先使用resetiosflags()清除旧有相应信息。
5.8 stringstream
(1)字符串转化数字
istringstream iss(str);
int n;
iss >> n;
(2)C++11提供如下函数简化字符串转数字
stoi() stol() stoul() stoll() stoull()
stof() stod() stold()
(3)数字转化字符串
int n;
ostringstream oss;
oss << n;
oss.str();
5.9 练习
(1)leecode
(2)实现空格分割字符串
vector<string> split(const string& str){
vector<string> res;
istringstream iss(str);
string s;
while(iss >> s){
res.push_back(s);
}
return res;
}
6、C++文件读写
文件:文件名+文件内容(有序数据集合)
文件名:字符序列
文件数据格式:二进制文本/文本文件
6.1 C++文件操作流程
1、打开文件
2、读写文件
3、关闭文件
6.2 打开/关闭文件
操作 | 代码 |
---|---|
定义读文件流对象 | ifstream读文件流对象 |
定义写文件流对象 | ofstream |
定义读写文件流对象 | fstream读写读文件流对象 |
成员函数打开文件 | 文件流对象.open(文件名,文件打开方式) |
构造函数打开文件 | 文件流类 对象(文件名,文件打开方式) |
判断文件是否打开 | !文件流对象 |
关闭文件 | 文件流对象.close(变量) |
6.3 文本文件读写
操作 | 代码 |
---|---|
提取运算符读文件 | 文件流对象>>变量 |
插入运算符写文件 | 文件流对象<<变量 |
成员函数读文件 | 文件流对象.get(变量) |
成员函数写文件 | 文件流对象.put(变量) |
6.4 二进制文件读写
操作 | 代码 |
---|---|
读函数 | read() |
写函数 | write() |
测试文件结束 | eof() |
6.5 文件打开方式
类型 | 代码 |
---|---|
读 | ios::in |
写 | ios::out |
添加末尾 | ios::app |
已存在文件 | ios::nocreae |
未打开文件 | ios::noreplace |
二进制 | ios::binary |
6.6 文件对象指针位置函数
操作 | 代码 |
---|---|
获取读位置 | 对象.tellg() |
获取写位置 | 对象.tellp() |
设置读位置 | 对象.seekg() |
设置写位置 | 对象.seekp() |
函数后缀p表述put(输出),后缀g表示get(输入)。
如果文件是以ios::app文本追加方式打开,指针位置默认在文件结束,其他情况默认在文件开头
6.7 文件对象状态函数
操作 | 代码 |
---|---|
判断文件对象状态是否正常 | 对象.good() |
重置文件对象状态 | 对象.clear() |
7、流文件类型
1、stream流文件
2、文件指针FILE*
7.1 流文件读写
(1)ifstream文件读
ifstream fin(文件路径);
fin >> 变量
fin.close();
(2)ofstream文件写
ofstream fout(文件路径);
fout << 变量
fout.close();
(3)fstream文件写
fstream fs(文件路径,ios::in|ios::out|ios::app);
if(fs){
fs << 变量;
fs.seekg(ios::beg);
fs >> 变量;
fs.close();
}
(4)fstream的打开模式是否创建不存在的文件
No. | 打开模式 | 是否创建不存在的文件 |
---|---|---|
1 | ios::in | 否 |
2 | ios::out | 是 |
3 | ios::in | ios::out |
4 | ios::in | ios::out |
(5)先读后写
#include <iostream>
#include <fstream>
using namespace std;
int main(){
fstream fs("text.txt",ios::in|ios::out|ios::app);
if(fs){
string str;
while(fs>>str){
cout << str << endl;
}
fs.clear();
while(cin>>str){
fs<< str << endl;
}
}
}
输出结果:
[root@westos_student70 05:文件]# ./a.out
qwe
qwe
[root@westos_student70 05:文件]# cat text.txt
qwe
qwe
(6)先写后读
#include <iostream>
#include <fstream>
using namespace std;
int main(){
fstream fs("test.txt",ios::in|ios::out|ios::app);
if(fs){
string str;
while(cin >> str){
fs << str << endl;
}
fs.seekg(ios::beg);
while(fs >> str)
cout << str << endl;
}else{
cerr << "file not exist" << endl;
}
}
7.2 文件指针FILE读写
(1)FILE文件指针读
FILE* fp = fopen(文件路径,"r");
fscanf(,fp);
fclose(fp);
(2)FILE文件指针写
FILE* fp = fopen(文件路径,"w");
fprintf(,fp);
fclose(fp);
对象的序列化和反序列化
序列化:把对象转化成文本/二进制
反序列化:把文本/二进制转化成对象
7.3 文件重定向
freopen(文件路径,操作,标准IO)
操作:读(r)写(w)
(1)重定向写
freopen("out.txt","w",stdout);
cout << "out data" <<endl;
(2)重定向读
freopen("in.txt","r",stdin);
string str;
cin >> str;
(3)几种常见的文件读取方式对比
ifstream + fin
freopen+cin+sync_with_stdio(false)
FILE* + fscanf
freopen+scanf
freopen+cin
(4)实现日志模块
freopen("test.log","w",stderr);
cerr << "FATAL";
cerr << "ERROR";
clog << "WARNING";
clog << "INFO";
clog << "DEBUG";