C++基础5:文件

1. 流

  • 流:数据从一个对象到另一个对象的传输。
  • 功能:标准输入输出+文件处理
分类 含义
文本流 一串ASCII字符
二进制流 一串二进制

2. 流类型

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

  • 标准I/O流
    • ios是抽象类
    • ostreamcoutclogcerr的类
    • istreamcin的类
  • 文件流类型
    • ifstream从文件读取数据
    • ofstream向文件写入数据
    • iofstream文件读写数据
  • 字符串流类型
    • istringstreamstring读取数据
    • ostringstreamstring写入数据
    • 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操作主要有如下五种:

  • 输入操作: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()

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提供如下函数简化字符串转数字

  • stoi() stol() stoul() stoll() stoull()

  • stof() stod() stold()

  • 数字转化字符串

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

练习

    vector<string> split(const string& str){
        vector<string> res;
        istringstream iss(str);
        string s;
        while(iss >> s){
            res.push_back(s);
        }
        return res;
    }

  • C++文件读写
    文件:文件名+文件内容(有序数据集合)
    文件名:字符序列
    文件数据格式:二进制文件/文本文件

  • C++文件操作流程

  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文件读
ifstream fin(文件路径);
fin >> 变量
fin.close();
  • ofstream文件写
ofstream fout(文件路径);
fout << 变量
fout.close();
  • fstream文件写
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文件指针读
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

实现日志模块

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

扩展阅读

  • <<C++程序设计语言(第4部分:标准库) 中文第四版>>:第38章 I/O流
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容