前文说过,ifstream是继承于istream,ofstream是继承于ostream,fstream是继承于iostream类,而他们应用的缓冲区类是filebuf。

对于这些类之间的关系,有趣味能够去查看我之前的文章:

c++规范输入输出流关系梳理

1. filebuf类介绍

filebuf类又比stringbuf类要简单一点,毕竟是对文件进行读写,首先在它的成员变量中找到了这样一条申明:

__file_type _M_file;

_M_file就是它外面的文件操作对象,那么探索一下__file_type到底是什么类型呢,通过跟代码发现它其实是一个类模板__basic_file的char实例,而__basic_file是围绕一个FILE类型的指针来进行操作的,而FILE这个类型大家其实就很相熟啦,它是c语言规范库外面操作文件的规范类型,个别是叫做文件指针,所以从这里就能够看出filebuf最终其实还是基于c语言的fopen等这一套文件操作函数去进行解决的。当然啦,在linux外面fopen其实又是基于它的零碎调用open函数来进行的,这个咱们晓得就好,就不再做开展啦。

当看到fopen的调用时,其实心田是挺惊喜的,因为fstream这一套货色以前也常常应用,然而呢,从来不晓得它的底层到底是怎么实现的,这次总算是晓得了一点。

1.1 filebuf类构造函数和析构函数

首先看一下filebuf的构造函数原型,如下:

//这里申明了一个无参构造函数

basic_filebuf();

#if __cplusplus >= 201103L

basic_filebuf(const basic_filebuf&) = delete;

//这里申明了一个入参为右值援用的挪动构造函数,所谓右值援用,它容许内容从一个filebuf对象挪动到另外一个filebuf对象,挪动实现当前,源filebuf对象将被销毁,不能再被应用,它没有产生任何拷贝的动作

basic_filebuf(basic_filebuf&&);

#endif

#if __cplusplus >= 201103L

basic_filebuf& operator=(const basic_filebuf&) = delete;

//同上,这里申明了一个挪动赋值函数

basic_filebuf& operator=(basic_filebuf&&);

#endif

//析构函数敞开文件

virtual

~basic_filebuf()

{ this->close(); }

小贴士:=delete是c++11的用法,在c++11以前要避免类对象被拷贝和赋值,就要把拷贝构造函数和赋值函数申明为private的,到了c++11就间接应用=delete来进行申明,它意味着这个函数不能被调用,否则编译就会报错。

从下面咱们能够看到filebuf类是不容许拷贝和赋值的,否则可能会产生多个对象操作同一个IO缓冲,就会导致诸多的问题,它只容许进行挪动,这样能保障任何时候同一个IO缓冲只有一个对象能够操作。

应用例子如下:

#include

using namespace std;

int main()

{

filebuf buf;

filebuf buf2(move(buf));//挪动构造函数,std::move用于生成一个绑定在buf上的filebuf&&

filebuf buf3 = move(buf);//挪动赋值函数

return 0;

}

1.2 open函数

函数原型如下:

//is_open用于判断文件是否是关上状态,返回true则示意文件是关上状态,否则就是敞开状态

bool

is_open() const throw()

{ return _M_file.is_open(); }

//__s示意文件名,__mode示意文件打开方式

__filebuf_type*

open(const char* __s, ios_base::openmode __mode);

#if __cplusplus >= 201103L

//同上,只是文件名应用了string示意而已

__filebuf_type*

open(const std::string& __s, ios_base::openmode __mode)

{ return open(__s.c_str(), __mode); }

#endif

//敞开文件

__filebuf_type*

close();

应用案例如下:

#include

#include

using namespace std;

int main()

{

filebuf buf;

if ( buf.open("aaa.txt", ios_base::in) == nullptr )

{

cout << "file open failed" << endl;

return -1;

}

if ( buf.is_open())

{

cout << "file is opened" << endl;

}

else

cout << "file is closed" << endl;

buf.close();//能够调用也能够不调用,析构函数会主动敞开

return 0;

}

还有其余函数这里就不多做介绍了,实践上来讲,咱们并不会间接应用filebuf,因为它只是一个工具人,是幕后奉献者,是藏于暗中滴,大多数时候,咱们都是间接应用ifstream和ofstream。

2. ifstream类

2.1 构造函数和析构函数

ifstream的构造函数除了默认无参构造函数以外,还基于filebuf的open函数申明了另外两个构造函数,fstream头文件中原型如下:

//默认的无参构造函数

basic_ifstream() : __istream_type(), _M_filebuf()

{ this->init(&_M_filebuf); }

//基于filebuf的open函数,申明了两个有参构造函数,默认是从文件读取数据

explicit

basic_ifstream(const char* __s, ios_base::openmode __mode = ios_base::in)

: __istream_type(), _M_filebuf()

{

this->init(&_M_filebuf);

this->open(__s, __mode);

}

#if __cplusplus >= 201103L

explicit

basic_ifstream(const std::string& __s,

ios_base::openmode __mode = ios_base::in)

: __istream_type(), _M_filebuf()

{

this->init(&_M_filebuf);

this->open(__s, __mode);

}

//同样的,拷贝构造函数不容许应用

basic_ifstream(const basic_ifstream&) = delete;

basic_ifstream(basic_ifstream&& __rhs)

: __istream_type(std::move(__rhs)),

_M_filebuf(std::move(__rhs._M_filebuf))

{ __istream_type::set_rdbuf(&_M_filebuf); }

#endif

~basic_ifstream()

{ }

#if __cplusplus >= 201103L

basic_ifstream&

operator=(const basic_ifstream&) = delete;

basic_ifstream&

operator=(basic_ifstream&& __rhs)

{

__istream_type::operator=(std::move(__rhs));

_M_filebuf = std::move(__rhs._M_filebuf);

return *this;

}

ifstream的拷贝构造函数和赋值函数也是间接被禁用的,那么再调用有参的构造函数后,默认的文件就被关上了,无需再次调用open函数,能够看到它的析构函数是什么都没有做的,所以ifstream须要显式的调用close函数,如果不显式调用的话,filebuf对象也会主动调用析构函数敞开文件,但如果filebuf调用close失败,就没方法晓得以后流的状态了。

2.2 swap和rdbuf函数

函数原型如下:

//替换两个ifstream

void swap(basic_ifstream& __rhs);

//返回一个指向以后filebuf缓冲区的指针

__filebuf_type*

rdbuf() const;

一个应用案例如下:

#include

#include

#include

using namespace std;

int main()

{

char szIn[32] = {0};

char szIn2[32] = {0};

ifstream in("aaa.txt", ios_base::in);//aaa.txt 内容:0123456789

ifstream in2("file.txt");//应用默认打开方式, file.txt 内容abcdefg带换行符

cout << "file aaa.txt size is " << in.rdbuf()->in_avail() << endl;

in.read(szIn, 3);

in2.read(szIn2, 3);

cout << "in's content is " << szIn << endl << "in2's conteng is " << szIn2 <

in.swap(in2);

memset(szIn, 0x00, sizeof(szIn));

memset(szIn2, 0x00, sizeof(szIn2));

in.read(szIn, sizeof(szIn));

in2.read(szIn2, sizeof(szIn2));

cout << "in's content is " << szIn << endl << "in2's conteng is " << szIn2 <

in.close();

in2.close();

return 0;

}

in_avail是streambuf类外面的一个函数,用于返回以后缓冲区长度。

编译后执行后果如下:

[root@mylinux ~]# ./a.out

file aaa.txt size is 10

in's content is 012

in2's conteng is abc

in's content is defg

in2's conteng is 3456789

[root@mylinux ~]#

通过后果能够看到swap函数并不会重置以后读的地位,根本是依照原样替换过去的。

2.3 open和close函数

函数原型如下:

bool

is_open();

bool

is_open() const;

void

open(const char* __s, ios_base::openmode __mode = ios_base::in);

void

open(const std::string& __s, ios_base::openmode __mode = ios_base::in);

void

close()

{

if (!_M_filebuf.close())

this->setstate(ios_base::failbit);

}

open函数和is_open函数用法与filebuf类基本一致,这里不再多说,次要是close,咱们能够看到它调用失败当前,会将以后流状态置为失败,所以规范的做法,还是显式的调用一下close函数比拟好。

2.4 ofstream类和fstream类

ofstream用于往文件写入数据,除了结构和调用open函数的时候,默认的关上模式是ios_base::out,其余所有函数应用都与ifstream截然不同,且用法也是一样的,包含fstream的函数用法,也是一样的,只是fstream默认关上模式是ios_base::in | ios_base::out,其余函数的用法这里不再多说。

总之,咱们要记住,如果要从文件读取数据,那么应用ifstream,如果要将数据写到文件,那么应用ofstream,如果既要读又要写,那么应用fstream。

3. stream流关上模式

前文说到文件打开方式ios_base::in和ios_base::out,实际上流打开方式不只这两种,上面就一一阐明一下:

流关上模式

阐明

ios_base::app

以追加形式关上文件,文件关上当前以后指针地位间接指到缓冲区最初面,总是从文件开端写入

ios_base::ate

关上时文件指针地位指向文件开端,但能够手动扭转指针地位,进而从以后地位开始写入

ios_base::binary

文件关上后在二进制模式下进行读写,依据我的察看,须要与ios_base::in或者ios_base::out联结应用,否则关上失败

ios_base::in

以只读形式关上文件,若文件存在则默认从最开始读取,如果文件不存在,则文件会关上失败

ios_base::out

以只写形式关上文件,若文件存在,则清空文件内容,若文件不存在,则创立一个空文件

ios_base::trunc

每次关上文件都间接清空文件内容,个别用于写入

在应用的时候,以’|’分隔,例如:ios_base::in|ios_base::out。

上面列几种不同场景下应用时的组合,如下:

以上场景都是针对文本文件进行读写的,如果想以同样的形式操作二进制文件,则在每个场景前面追加一个ios_base::binary即可。

这里在应用ifstream的时候要留神,不论是构造函数关上还是手动调用open函数关上文件,它在咱们指定的文件模式上会另外追加一个ios_base::in,如下:

void

open(const char* __s, ios_base::openmode __mode = ios_base::in)

{

if (!_M_filebuf.open(__s, __mode | ios_base::in))

this->setstate(ios_base::failbit);

else

// _GLIBCXX_RESOLVE_LIB_DEFECTS

// 409. Closing an fstream should clear error state

this->clear();

}

同理,ofstream则会默认追加一个ios_base::out,但fstream则没有默认追加,不指定就默认ios_base::in|ios_base::out,如果指定了模式,则以指定的为准。

不晓得大家有没有发现一点,这里咱们始终没有说到ios_base::ate的应用场景,是认为我始终想不进去有用这个的必要性,惟一的场景是想关上文件的时候指针指向开端,而后续又可能从其余地位进行读写,就应用它,但在应用ofstream的时候如果指定了ios_base::ate,它又会因为默认追加的ios_base::out而清空文件,这时惟一的办法是应用fstream类,并指定模式为ios_base::ate|ios_base::in|ios_base::out,这样才既没有清空文件,也满足了咱们的应用场景。

c语言ofstream未定义标识符,关于c++:c中ifstream及ofstream超详细说明相关推荐

  1. c语言ofstream未定义标识符,C++ 标准文件的写入读出(ifstream,ofstream)

    注: "< ">>", 析取器,从流输出数据, ifstream和ofstream主要包含在头文件中. fstream可对打开的文件进行读写操作 ifs ...

  2. c语言ok未定义标识符,C语言中宏的相关知识 - osc_y7ckpzr9的个人空间 - OSCHINA - 中文开源技术交流社区...

    2019/04/27 16:02 1.宏的定义:宏定义就是预处理命令的一种,它允许用一个标识符来表示一个字符串.格式如下: #define name(宏名) stuff(字符串) 本质就是使用宏名去替 ...

  3. c语言中未定义标识符,未定义标识符

    源自:4-5 C++新特性以及输入输出演示 未定义标识符 代码: #include "iostream" #include "stdlib.h" #includ ...

  4. c语言未定义标识符using,c++未定义标识符怎么办?

    满意答案 lg254839555 2013.07.13 采纳率:57%    等级:12 已帮助:8508人 #include #include using namespace std; struct ...

  5. VS2019未定义标识符detect该怎么解决

    如果在使用VS2019的过程中出现了"未定义标识符: detect"的错误提示,请检查下列几点: 确保在使用到标识符detect之前,你已经正确地包含了对应的头文件. 确保你在代码 ...

  6. OpenCV学习中cvtColor与cvCvtColor的区别,及未定义标识符问题解决

    一.cvCvtColor cvCvtColo为C语言风格接口 - void cvCvtColor(const CvArr src, CvArr* dst, int code)** CvMat是C中的一 ...

  7. Visual Studio 调试(Dubug)模式下的“未定义标识符”

    原文:https://blog.csdn.net/pijk55556/article/details/60969091 Visual Studio 调试(Dubug)模式下的"未定义标识符& ...

  8. VS中未定义标识符cout,endl

    VS中未定义标识符 vs2017中显示未定义标识符cout,endl. 一种方法是:先看有没有包含输入输出流#include<iostream>,以及命名空间using namespace ...

  9. VS2019 莫名其妙出现: C2059 语法错误:“}“,C2143 语法错误:缺少“;“(在“}“的前面),C2065 未定义标识符,C2039 不是““的成员等

    一.问题 VS2019 莫名其妙出现: C2059 语法错误:"}" C2143 语法错误:缺少";"(在"}"的前面) C2447     ...

最新文章

  1. python2和python3区别
  2. [architecture]-ARMV7架构下Linux Kernel的Userspace进程切换时保存和恢复哪些寄存器
  3. JavaScript 原型链学习(二)原型的动态性
  4. 罗森伯格成功布线中国海关博物馆
  5. #Spring代理的简单例子#
  6. iOS App如何连接外设
  7. 254. Factor Combinations
  8. 少拿游戏来骗我,虚幻引擎5上的《黑客帝国》全新体验,画面帅到爆
  9. 爬虫入门四(多线程爬虫)
  10. 只需两步手把手教你玩转图像识别
  11. Linux 命令(131)—— usermod 命令
  12. Lucene入门与使用(一) [转]
  13. NGN学习笔记4——软交换中的协议2—Megaco/H.248
  14. SpringMVC form中commandName报错问题
  15. EDA程序设计--出租车计费器
  16. Python连载(0011): 十分钟理解元组
  17. UNIX v6 fork()源码分析
  18. iOS GameCenter
  19. JVM 重点知识点总结
  20. 谷歌浏览器 抖动 chrome 上下抖动 问题解决

热门文章

  1. IntelliJ IDEA快捷键大全 + 动图演示,建议收藏!
  2. Rockchip | Rockchip Graphics与Display
  3. 看福田奥铃如何玩转信息化魔方
  4. 比尔盖茨致青年的黄金准则(双语)
  5. 吊打面试官之一面自我介绍
  6. 软件架构设计之系统耦合性拆分
  7. 字节(Byte)、位(bit)
  8. mysql 存byte数组中_byte数组存储到mysql
  9. python之数据分析与展示(numpy、matplotlib、pandas)
  10. 1型糖尿病青年患者易诱发心脏疾病英语科普English