5 文件

5.1 流

  • 流:
    数据从一个对象到另一个对象的传输。
  • 功能
    标准输入输出+文件处理

分类

含义

文本流

一串ASCII字符

二进制流

一串二进制

5.2 流类型

标准库定义了三大类流类型:标准I/O流、文件流、字符串流

  • 标准I/O流
    ios是抽象类
    ostreamcout、clog、cerr的类
    istreamcin的类
  • 文件流类型
    ifstream从文件读取数据
    ofstream向文件写入数据
    iofstream文件读写数据
  • 字符串流类型
    istringstreamstring读取数据
    ostringstreamstring写入数据
    iostringstream读写string数据

5.3 流对象

通常标准I/O流对象是全局对象不需要定义,而文件流对象和字符串流对象需要用户定义。

标准I/O流对象有以下四个:

全局流对象

名称

缓存

cout

标准输出流

带缓存

cin

标准输入流

带缓存

clog

标准日志流

带缓存

cerr

标准错误流

无缓存

注:流对象通常都不能复制。

5.4 流对象状态

流对象状态在某一个时刻必定处于以下四个状态之一。

状态

含义

good()

前一个流操作成功

eof()

到输入尾/文件尾

fail()

发生意外事情(读取失败)

bad()

发生意外严重事情(磁盘读取失败)

5.5 I/O操作

  • I/O操作主要有如下五种:
    输入操作:in >> x或者getline(in,s) 输出操作:out << x 操作符
    流状态
    格式化
  • 输出流默认设置

类型

进制

宽度

对齐

填充

精度

整数

十进制

0

右对齐

空格

1

实数

十进制

0

右对齐

空格

6位数

字符串

-

0

右对齐

空格

字符串实际长度

  • 格式控制
  • 格式控制成员函数
流对象.格式控制函数(实参)
  • 预定义格式控制函数
预定义格式控制函数(实参)
  • 流的输出控制格式

作用

格式控制成员函数

预定义格式控制函数

预定义格式控制符/操作子

效果持续

进制

flags() setf() unsetf()

setiosflags()

dec oct hex showbase

能持续

宽度

width(n)

setw(n)

-

不能持续

对齐

flags() setf() unsetf()

setiosflags()

right left internal

能持续

填充

fill(c)

setfill(c)

-

能持续

精度

precision(n)

setprecision(n)

-

能持续

  • 流的输出控制格式:dec oct hex
  • 数据输入成员函数
    字符输入成员函数:get() 字符串输入成员函数:getline()
  • 数据输出成员函数:put()

5.6 输出格式控制

5.6.1 对齐方式

flag

manipulator

作用

ios::left

left

居左

ios::right

right

居右

ios::internal

internal

输出符号或进制后填充

  • 实例:操作子方式和成员函数方式
#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

作用

是否默认

ios::dec

dec

十进制


ios::oct

oct

八进制


ios::hex

hex

十六进制


ios::uppercase

uppercase

使用大写输出十六进制


ios::showbase

showbase

输出带有进制的字符


  • 成员函数方式
#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

作用

是否默认

精度

ios::defaultfloat

默认浮点数格式


最多保留多少位数字

ios::scientific

科学计数法输出浮点数


小数点后最多保留多少位数字

ios::fixed

定点数方式输出实数


小数点后最多保留多少位数字

注:
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

作用

默认

ios::boolalpha

boolalpha

bool值以字符串true/false输出


5.6.5 其他

flag

manipulator

作用

默认

ios::showpos

showpos

输出十进制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 istringstreamostringstream

  • 头文件:
#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 打开/关闭文件

操作

代码

定义读文件流对象

ifstream 读文件流对象

定义写文件流对象

ofstream 写读文件流对象

定义读写文件流对象

fstream 读写读文件流对象

成员函数打开文件

文件流对象.open(文件名,文件打开方式)

构造函数打开文件

文件流类 对象(文件名,文件打开方式)

判断文件是否打开

!文件流对象

关闭文件

文件流对象.close(变量)

5.8.2 文本文件读写

操作

代码

提取运算符读文件

文件流对象 >> 变量

插入运算符写文件

文件流对象 << 变量

成员函数读文件

文件流对象.get(变量)

成员函数写文件

文件流对象.put(变量)

5.8.3 二进制文件读写

操作

代码

读函数

read()

写函数

write()

测试文件结束

eof()

  • 实例:
// 以二进制输入输出,查看输出: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 文件打开方式

类型

代码


ios::in


ios::out

添加末尾

ios::app

已存在文件

ios::nocreate

未打开文件

ios::noreplace

二进制

ios::binary

5.8.5 文件对象指针位置函数

操作

代码

获取读位置

对象.tellg()

获取写位置

对象.tellp()

设置读位置

对象.seekg()

设置写位置

对象.seekp()

  • 注:
    函数后缀p表示put(输出),后缀g表示get(输入)。
    如果文件是以ios::app文本追加方式打开,指针位置默认在文件结束,其他情况默认在文件开头。

5.8.6 文件对象状态函数

操作

代码

判断文件对象状态是否正常

对象.good()

重置文件对象状态

对象.clear()

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的打开模式是否创建不存在的文件

打开模式

是否创建不存在的文件

ios::in


ios::out


ios::in/ios::out


ios::in/ios::out/ios::app


  • 实例:先读后写
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