首页 > 编程知识 正文

c++编程格式,c++ 标识符

时间:2023-05-04 10:01:04 阅读:153982 作者:4426

如上所述,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类型的指针为中心进行的,这是在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

//析构函数关闭文件

虚拟

~basic_filebuf ()

{ this-close (; }小贴士:=delete是c 11的用法,在c 11以前为了防止类对象的复制和赋值,必须将复制构造函数和赋值函数声明为private,到了c 11时直接使用=delete进行声明。 这意味着不调用此函数,否则编译将报告错误。

根据以上内容,可以看出filebuf类不允许复制和赋值。 否则,多个对象可能会操作同一个IO缓冲区,从而导致许多问题。 它只允许移动,随时允许同一IO缓冲区只操作一个对象。

使用案例如下:#include

using namespace std;

int main () )

{

文件缓冲区;

filebufbuf2(move ) buf ); //移动构造函数std:move用于生成绑定到buf的filebuf

filebufbuf3=move(buf; //移动赋值函数

返回0;

}

1.2 open函数

函数原型如下。 //is_open用于确定文件是否已打开,返回true表示文件已打开,否则表示文件已关闭

布尔

is_open(constthrow ) )。

{ return _M_file.is_open (; }

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

__filebuf_type*

open(constchar*_s,IOs _ base : open mode _ _ mode );

#if __cplusplus=201103L

//同上,只是在文件名中使用了字符串表示

__filebuf_type*

open(constSTD33603360string_s,IOs_base33603360openmode_mode ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) )

{returnopen(_s.c_str ) )、__mode ); }

#endif

//关闭文件

__filebuf_type*

类(;

使用案例如下:#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,这样才既没有清空文件,也满足了我们的使用场景。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。