C++

C++基础5:文件

2017-07-18  本文已影响214人  jdzhangxin

1. 流

分类 含义
文本流 一串ASCII字符
二进制流 一串二进制

2. 流类型

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

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操作主要有如下五种:


类型 进制 宽度 对齐 填充 精度
整数 十进制 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) - 能持续

1. 对齐方式

flag manipulator 作用
ios::left left 居左
ios::right right 居右
ios::internal internal 输出符号或进制后填充
#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;
}
#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;
}
#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;
}

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;
}

3. 浮点数输出格式

flag 作用 是否默认 精度
ios::defaultfloat 默认浮点数格式 最多保留多少位数字
ios::scientific 科学计数法输出浮点数 小数点后最多保留多少位数字
ios::fixed 定点数方式输出实数 小数点后最多保留多少位数字

如果浮点数没有小数时默认不显示小时点,使用ios::showpoint可以强制输出浮点数时,必须带小数点。

定点数方式比浮点数方式更精确
取浮点数精确度时,设置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;
}

4.布尔类型输出格式

flag manipulator 作用
ios::boolalpha boolalpha bool值以字符串true/false输出

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非常合适。

问题

  1. 浮点数八进制/十六进制输出结果?
  2. 下列代码为什么能转化成十六进制?
#include <iostream>
#include <iomanip> // setiosflags() , ios::hex
using namespace std;
int main(){
        cout << setiosflags(ios::hex) << 10 << endl;
}

最新版C++的iostream库中,在使用setiosflags()前要先使用resetiosflags()清除旧有相应信息。

cout << resetiosflags(ios::basefield)<< setiosflags(ios::hex) << 10 << endl;

以下三类格式化在使用setiosflags(),要先使用resetiosflags()清除旧有相应信息。



stringstream

istringstream iss(str);
int n;
iss >> n;

C++11提供如下函数简化字符串转数字

int n;
ostringstream oss;
oss << n;
oss.str();

  1. 打开文件
  2. 读写文件
  3. 关闭文件
操作 代码
定义读文件流对象 ifstream 读文件流对象
定义写文件流对象 ofstream 写读文件流对象
定义读写文件流对象 fstream 读写读文件流对象
成员函数打开文件 文件流对象.open(文件名,文件打开方式)
构造函数打开文件 文件流类 对象(文件名,文件打开方式)
判断文件是否打开 !文件流对象
关闭文件 文件流对象.close(变量)
操作 代码
提取运算符读文件 文件流对象 >> 变量
插入运算符写文件 文件流对象 << 变量
成员函数读文件 文件流对象.get(变量)
成员函数写文件 文件流对象.put(变量)
操作 代码
读函数 read()
写函数 write()
测试文件结束 eof()
类型 代码
ios::in
ios::out
添加末尾 ios::app
已存在文件 ios::nocreate
未打开文件 ios::noreplace
二进制 ios::binary
操作 代码
获取读位置 对象.tellg()
获取写位置 对象.tellp()
设置读位置 对象.seekg()
设置写位置 对象.seekp()
  • 函数后缀p表示put(输出),后缀g表示get(输入)。
  • 如果文件是以ios::app文本追加方式打开,指针位置默认在文件结束,其他情况默认在文件开头。
操作 代码
判断文件对象状态是否正常 对象.good()
重置文件对象状态 对象.clear()

流式文件类型

  1. stream流文件
  2. 文件指针FILE*

stream流文件读写

ifstream fin(文件路径);
fin >> 变量
fin.close();
ofstream fout(文件路径);
fout << 变量
fout.close();
fstream fs(文件路径,ios::in|ios::out|ios::app);
if(fs){
  fs << 变量;
  fs.seekg(ios::beg);
  fs >> 变量;
  fs.close();
}

fstream的打开模式是否创建不存在的文件

No. 打开模式 是否创建不存在的文件
1 ios::in
2 ios::out
3 `ios::in ios::out`
4 `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;
    }

文件指针FILE读写

FILE* fp = fopen(文件路径,"r");
fscanf(,fp);
fclose(fp);
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;

几种常见的文件读取方式对比

实现日志模块

freopen("test.log","w",stderr);
cerr << "FATAL";
cerr << "ERROR";
clog << "WARNING";
clog << "INFO";
clog << "DEBUG";

扩展阅读

上一篇 下一篇

猜你喜欢

热点阅读