5 文件
5.1 流
- 流:
数据从一个对象到另一个对象的传输。 - 功能
标准输入输出+文件处理
分类 | 含义 |
文本流 | 一串ASCII字符 |
二进制流 | 一串二进制 |
5.2 流类型
标准库定义了三大类流类型:标准I/O流、文件流、字符串流
- 标准I/O流
ios
是抽象类ostream
是cout、clog、cerr
的类istream
是cin
的类 - 文件流类型
ifstream
从文件读取数据ofstream
向文件写入数据iofstream
文件读写数据 - 字符串流类型
istringstream
从string
读取数据ostringstream
向string
写入数据iostringstream
读写string
数据
5.3 流对象
通常标准I/O
流对象是全局对象不需要定义,而文件流对象和字符串流对象需要用户定义。
标准I/O
流对象有以下四个:
全局流对象 | 名称 | 缓存 |
| 标准输出流 | 带缓存 |
| 标准输入流 | 带缓存 |
| 标准日志流 | 带缓存 |
| 标准错误流 | 无缓存 |
注:流对象通常都不能复制。
5.4 流对象状态
流对象状态在某一个时刻必定处于以下四个状态之一。
状态 | 含义 |
| 前一个流操作成功 |
| 到输入尾/文件尾 |
| 发生意外事情(读取失败) |
| 发生意外严重事情(磁盘读取失败) |
5.5 I/O
操作
-
I/O
操作主要有如下五种:
输入操作:in >> x
或者getline(in,s)
输出操作:out << x
操作符
流状态
格式化 - 输出流默认设置
类型 | 进制 | 宽度 | 对齐 | 填充 | 精度 |
整数 | 十进制 | 0 | 右对齐 | 空格 | 1 |
实数 | 十进制 | 0 | 右对齐 | 空格 | 6位数 |
字符串 | - | 0 | 右对齐 | 空格 | 字符串实际长度 |
- 格式控制
- 格式控制成员函数
流对象.格式控制函数(实参)
- 预定义格式控制函数
预定义格式控制函数(实参)
- 流的输出控制格式
作用 | 格式控制成员函数 | 预定义格式控制函数 | 预定义格式控制符/操作子 | 效果持续 |
进制 |
|
|
| 能持续 |
宽度 |
|
| - | 不能持续 |
对齐 |
|
|
| 能持续 |
填充 |
|
| - | 能持续 |
精度 |
|
| - | 能持续 |
- 流的输出控制格式:
dec oct hex
- 数据输入成员函数
字符输入成员函数:get()
字符串输入成员函数:getline()
- 数据输出成员函数:
put()
5.6 输出格式控制
5.6.1 对齐方式
flag | manipulator | 作用 |
|
| 居左 |
|
| 居右 |
|
| 输出符号或进制后填充 |
- 实例:操作子方式和成员函数方式
#include <iostream>
#include <iomanip> //sete()
using namespace std;
int main(){
// 默认数字右对齐
//成员函数方式
cout.width(6);
cout.flags(ios::left); // 设置左对齐
cout.fill('=');
cout << 10 << endl;
cout.width(6);
cout << 10000 << endl;
cout.width(6);
cout << 1000 << endl;
cout.width(6);
cout << 100 << endl;
cout.width(6);
cout << 20 << endl;
//操作子方式
cout << setw(6) << left << setfill('-') << 10 << endl;
cout << setw(6) << 10000 << endl;
cout << setw(6) << 1000 << endl;
cout << setw(6) << 100 << endl;
cout << setw(6) << 20 << endl;
cout << setw(6) << "abc" << endl;
}
10====
10000=
1000==
100===
20====
10----
10000-
1000--
100---
20----
abc---
5.6.2 整数输出格式
flag | manipulator | 作用 | 是否默认 |
|
| 十进制 | 是 |
|
| 八进制 | 否 |
|
| 十六进制 | 否 |
|
| 使用大写输出十六进制 | 否 |
|
| 输出带有进制的字符 | 否 |
- 成员函数方式
#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;
}
- 操作子方式
#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;
}
5.6.3 浮点数输出格式
flag | 作用 | 是否默认 | 精度 |
| 默认浮点数格式 | 是 | 最多保留多少位数字 |
| 科学计数法输出浮点数 | 否 | 小数点后最多保留多少位数字 |
| 定点数方式输出实数 | 否 | 小数点后最多保留多少位数字 |
注:
1、如果浮点数没有小数时默认不显示小时点,使用ios::showpoint
可以强制输出浮点数时,必须带小数点。
2、定点数方式比浮点数方式更精确
取浮点数精确度时,设置ios::fixed
- 成员函数方式
#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;
}
- 操作子方式
#include <iostream> // std::cout, std::fixed, std::scientific
#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;
}
- 混合方式
#include <iostream> // std::cout, std::fixed, std::scientific
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 << '\n' << b << '\n' << c << '\n\n'
std::cout << "fixed:\n" << std::fixed;
std::cout << a << '\n' << b << '\n' << c << '\n\n'
std::cout << "scientific:\n" << std::scientific;
std::cout << a << '\n' << b << '\n' << c << '\n\n';
return 0;
}
5.6.4 布尔类型输出格式
flag | manipulator | 作用 | 默认 |
|
| 把 | 否 |
5.6.5 其他
flag | manipulator | 作用 | 默认 |
|
| 输出十进制0或者正数时,带+号 | 否 |
- 成员函数方式
#include <iostream> // std::cout, std::showpos, std::noshowpos
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;
}
- 操作子方式
#include <iostream> // std::cout, std::showpos, std::noshowpos
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;
}
注: 复数虚部a+bi使用showpos
非常合适。
5.7 istringstream
和ostringstream
- 头文件:
#include <sstream>
-
istringstream
:字符串转数字 -
ostringstream
: 数字转字符串 - 实例:
#include <iostream>
#include <iomanip>
using namespace std;
int Stoi(const string& s){
int n;
istringstream iss(s);
iss >> n;
return n;
}
string Itos(int n){
ostringstream oss;
oss << n;
return oss.str();
}
int main(){
int a = 100;
ostringstream oss; // 数字转字符串
oss << a;
cout << oss.str() << endl;
cout << Itos(a) << endl;
istringstream iss("12345"); // 字符串转数字
iss >> a;
cout << a << endl;
cout << Stoi("12345") << endl;
cout << (stoi("1000")+123) << endl;
}
100
100
12345
12345
1123
- C++11提供如下函数简化字符串转数字
stoi() stol() stoul() stoll() stoull()
stof() stod() stold()
5.8 文件读写
- C++文件读写
文件:文件名+文件内容(有序数据集合)
文件名:字符序列
文件数据格式:二进制文件/文本文件 - C++文件操作流程
打开文件
读写文件
关闭文件
5.8.1 打开/关闭文件
操作 | 代码 |
定义读文件流对象 |
|
定义写文件流对象 |
|
定义读写文件流对象 |
|
成员函数打开文件 | 文件流对象. |
构造函数打开文件 | 文件流类 对象(文件名,文件打开方式) |
判断文件是否打开 |
|
关闭文件 | 文件流对象. |
5.8.2 文本文件读写
操作 | 代码 |
提取运算符读文件 | 文件流对象 >> 变量 |
插入运算符写文件 | 文件流对象 << 变量 |
成员函数读文件 | 文件流对象. |
成员函数写文件 | 文件流对象. |
5.8.3 二进制文件读写
操作 | 代码 |
读函数 |
|
写函数 |
|
测试文件结束 |
|
- 实例:
// 以二进制输入输出,查看输出:od test od -A x -t x1z -v
#include <iostream>
#include <fstream>
using namespace std;
int main(){
cout << ios::out << endl; // 1000
cout << ios::in << endl; // 0100
cout << ios::binary << endl; // 0010
// ios::out|ios::binary // 1010
//
int n = 1000;
ofstream fout("./test",ios::out|ios::binary);
if(!fout){
cerr << "文件打开失败" << endl;
}
//fout << n << endl;
fout.write((const char*)&n,sizeof(n));
fout.close();
ifstream fin("./test",ios::in|ios::binary);
if(!fin){
cerr << "文件打开失败" << endl;
}
int m;
//fin >> m;
fin.read((char*)&m,sizeof(m));
fin.close();
cout << dec << m << endl;
}
5.8.4 文件打开方式
类型 | 代码 |
读 |
|
写 |
|
添加末尾 |
|
已存在文件 |
|
未打开文件 |
|
二进制 |
|
5.8.5 文件对象指针位置函数
操作 | 代码 |
获取读位置 | 对象. |
获取写位置 | 对象. |
设置读位置 | 对象. |
设置写位置 | 对象. |
- 注:
函数后缀p
表示put
(输出),后缀g
表示get
(输入)。
如果文件是以ios::app
文本追加方式打开,指针位置默认在文件结束,其他情况默认在文件开头。
5.8.6 文件对象状态函数
操作 | 代码 |
判断文件对象状态是否正常 | 对象. |
重置文件对象状态 | 对象. |
5.9 stream
流文件读写
-
ifstream
文件读
ifstream fin(文件路径);
fin >> 变量
fin.close();
-
ofstream
文件写
ofstream fout(文件路径);
fout << 变量
fout.close();
实例:
#include <iostream>
#include <fstream>
using namespace std;
int main(){
cout << ios::out << endl; // 1000
cout << ios::in << endl; // 0100
cout << ios::binary << endl; // 0010
// ios::out|ios::binary // 1010
//
int n = 1000;
ofstream fout("./test",ios::out);
if(!fout){
cerr << "文件打开失败" << endl;
}
fout << n << endl;
fout.close();
ifstream fin("./test",ios::in);
if(!fin){
cerr << "文件打开失败" << endl;
}
int m;
fin >> m;
fin.close();
cout << m << endl;
}
16
8
4
1000
[root@localhost 5]# cat test
1000
-
fstream
文件读和写
fstream fs(文件路径,ios::in|ios::out|ios::app);
if(fs){
fs << 变量;
fs.seekg(ios::beg);
fs >> 变量;
fs.close();
}
-
fstream
的打开模式是否创建不存在的文件
打开模式 | 是否创建不存在的文件 |
| 否 |
| 是 |
| 否 |
| 是 |
- 实例:先读后写
fstream fs("test.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;
}
}
- 实例:先写后读
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;
// 后续如果对fs操作,需要清空fs状态
}else{
cerr << "file not exist " << endl;
}
5.10 文件指针FILE
读写
-
FILE
文件指针读
FILE* fp = fopen(文件路径,"r");
fscanf(,fp);
fclose(fp);
-
FILE
文件指针写
FILE* fp = fopen(文件路径,"w");
fprintf(,fp);
fclose(fp);
对象的序列化与反序列化
序列化: 把对象转化成文本/二进制
反序列化: 把文本/二进制转化成对象
- 文件重定向
freopen(文件路径,操作,标准IO)
操作:读(r
) 写(w
)
- 重定向写
freopen("out.txt","w",stdout);
cout << "out data" <<endl;
- 重定向读
freopen("in.txt","r",stdin);
string str;
cin >> str;
- 几种常见的文件读取方式对比
ifstream + fin
freopen+cin+sync_with_stdio(false)
FILE* + fscanf
freopen+scanf
freopen+cin