文章目录
- 1.文件流
- 2.打开文件
- 3.读写文件
- 4.流状态
- 5.文件关闭
1.文件流
- ofstream,由ostream派生而来,用于写文件
重载了插入运算符<< - ifstream,由istream派生而来,用于读文件
重载了提取运算符>> - fstream,由iostream派生而来,用于读写文件
重载了<<和>>
2.打开文件
- 说明了流对象之后,可使用函数open()打开文件。
文件的打开即是在流与文件之间建立一个连接 - 函数原型
void open (const char* filename, int mode = ios::out, int prot = _SH_DENYNO);
参数:
filename:文件的名称,可以包含(绝对和相对)路径
mode:文件打开模式
prot:保护模式
- eg:P59\01.cpp
#include <cassert>
#include <iostream>
#include <fstream>
using namespace std;
int main(void)
{
//定义一个文件输出流对象
ofstream fout;
//open的第二和第三参数都有默认值
fout.open("test.txt");
//这2行等价于下面的1行
//ofstream fout;
//fout.open("test.txt");
ofstream fout("test.txt");//通过构造函数的方式打开
//判断打开是否成功或者失败
//方法1:判断文件流缓冲区是否处于打开的状态
//ofstream文件流对象,子对象:filebuf
if (fout.is_open())
{
cout<<"succ"<<endl;
}
else
{
cout<<"failed"<<endl;
}
//方法2:判断文件流状态是否处于正常状态
//good方法判断流状态是否正常
if (fout.good())
{
cout<<"succ"<<endl;
}
else
{
cout<<"failed"<<endl;
}
//方法3:对象作为条件
//重载了类型转换运算符void *
if (fout)
{
cout<<"succ"<<endl;
}
else
{
cout<<"failed"<<endl;
}
//方法4,重载!的运算符
if (!fout)
{
cout<<"failed"<<endl;
}
else
{
cout<<"succ"<<endl;
}
//方法5,推荐使用断言的方式判断文件是否打开成功
assert(fout);
fout.close();
return 0;
}
- 测试:在工程目录底下产生了一个文件。.vcproj后缀的目录就是工程目录。
若在这执行,当前目录就是工程目录
如果直接运行可执行程序,则当前目录就是可执行文件当前所在的目录- if (fout.is_open())的含义
- _Filebuffer实际上是_Myfb
- _Myfb是basic_filebuf,也就是说:ofstream文件流对象内部有一个子对象:文件流缓冲区_Filebuffer(也就是说ostream类与basic_filebuf类是组合的关系)
- if (fout) 的含义
- F11跟踪进来 ,发现重载了类型转换运算符void *,返回指针
将fout对象转换为void *无类型指针,如果流的状态是失败fail()的状态,则返回空指针,否则成功返回this指针(指向对象自身的指针,肯定不是空指针),也就是说返回的是&fout - 文件打开模式
- 其他说明:
(1)ios::out和ios_base::out是一样的。 - ios::out实际上是一个枚举,其类型实际上在_Iosb中
- ios_base继承至_Iosb,说明out这些枚举量是在_Iosb类中定义的,那么可以它的派生类就可以访问这些枚举常量,ios又继承至ios_base,所以也可以访问这些枚举常量
- (2)即使模式是ios::in,打开的时候,肯定会或上一个out模式,写入模式,因为ofstream是用于写入文件的
- 保护模式
(1)_SH_DENYRW,这里的拒绝的含义是:拒绝的是其他进程对文件进行读写
_SH_DENYWR,其他进程可以读,不能写;
_SH_DENYRD,其他进程可以写,但是不能读;
_SH_DENYNO,允许其他进程读取和写入文件,这是默认的保护模式;
_SH_SECURE,允许其他进程读,但是不能写;
一般情况下,不会填写这些参数;
(2)默认值如下:
将该值放到这里,用助手可以go一下,
实际上该值是
继续go一下,保护模式5个值
- 文件打开的几点说明(1)
文件打开也可以通过构造函数打开,eg:ofstream fout(“out.txt”, ios::out);
若构造函数没有接收参数的时候,在构造函数中不会进行任何操作
若构造函数有接收参数的时候,在构造函数中调用open函数 - 文件打开的几点说明(2)
文件的打开方式可以为上述的一个枚举常量,也可以为多个枚举常量构成的按位或表达式 - 文件打开的几点说明(3)
使用open成员函数打开一个文件时,若由字符指针参数所指定的文件不存在,则建立该文件
eg:P59\02.cpp
#include <cassert>
#include <iostream>
#include <fstream>
using namespace std;
int main(void)
{
//ifstream打开文件,若文件不存在,则不会创建文件
ifstream fin("test2.txt");
assert(fin);
fout.close();
return 0;
}
断言失败
- 文件打开的几点说明(4)
当打开方式中不含有ios::ate或者ios::app选项时,则文件指针被自动移动到文件的开始位置,即字节地址为0的位置 - 文件打开的几点说明(5)
从效果上看ofstream指定out模式等同于指定了out和trunc模式 - 文件打开的几点说明(6)
默认情况下,输入输出流fstream对象以in和out模式同时打开 - 文件打开的几点说明(7)
当文件同时以in和out打开时不会清空 - 文件打开的几点说明(8)
如果只使用out模式,而不指定in模式,则文件会清空现有数据 - 文件打开的几点说明(9)
如果同时指定了out与app,不会清空 - 文件打开的几点说明(10)
如果打开文件时指定了trunc模式,则无论是否同时指定了in模式,文件同样会被清空 - eg:P59\03.cpp
#include <cassert>
#include <iostream>
#include <fstream>
using namespace std;
int main(void)
{
//文件输出流ofstream默认打开模式是ios::out(没有指任何模式时)
//输入流ifstream默认打开模式是ios::in
ofstream fout("test.txt", ios::out);//等价于指定了ios::out|ios::trunc模式
//当文件同时以in和out打开时不会清空
ofstream fout("test.txt", ios::out|ios::in);
//如果打开文件时指定了trunc模式,则无论是否同时指定了in模式,文件同样会被清空
ofstream fout("test.txt", ios::out|ios::in|ios::trunc);
//如果同时指定了out与app,不会清空
ofstream fout("test.txt", ios::out|ios::in|ios::app);
assert(fin);
fout.close();
return 0;
}
- app与ate的区别:P59\04.cpp
#include <cassert>
#include <iostream>
#include <fstream>
using namespace std;
int main(void)
{
//差别1
//如果同时指定了out与app,不会清空
ofstream fout("test.txt", ios::out|ios::in|ios::app);
//差别2,文件会被清空
ofstream fout("test.txt", ios::out|ios::ate);
//文件不会被清空
ofstream fout("test.txt", ios::out|ios::in|ios::ate);
//往文件里写入一些数据,因为输出流对象重载了<<运算符
ofstream fout1("test3.txt", ios::in | ios::out | ios::ate);
ofstream fout2("test3.txt", ios::in | ios::out | ios::ate);
//追加方式1
//结果发现:输出了Y
//第一个输出流对象填了一个X,第二个输出流对象填了个Y
//所以第二次把前面的X给覆盖了,即:一旦打开文件,文件指针就定位到了文件末尾
//ate是打开文件后,立即将文件定位在文件尾
fout1 << "X";
fout2 << "Y";
//追加方式2
//结果发现,输出了XY
//在写入的时候定位到末尾,先定位到末尾,写入X,接着再定位到末尾,再写入Y
//app是在写之前定位到末尾
ofstream fout1("test3.txt", ios::in | ios::out | ios::app);
ofstream fout2("test3.txt", ios::in | ios::out | ios::app);
fout1 << "X";
fout2 << "Y";
fout1.close();
fout2.close();
// app 与 trunc 不能共存,流状态为fail
ofstream fout3( "test.txt", ios::out | ios::app | ios::trunc);
assert(fout3);//会失败
// app 和 ate 可以共存,以app为准
ofstream fout1( "test3.txt", ios::in | ios::out | ios::app | ios::ate);
ofstream fout2( "test3.txt", ios::in | ios::out | ios::app | ios::ate);
assert(fout1);
assert(fout2);
fout1 << "X";
fout2 << "Y"; //Y 输出在 X 的后面
return 0;
}
- 文件打开模式的有效组合
(1)app与trunc不能同时存在, app 和 ate 可以共存,以app为准
(2)所有的打开模式组合还可以添加ate模式。对这些模式添加ate模只会改变文件打开时的初始定位,将文件定位于文件末尾处。
3.读写文件
- 见上
4.流状态
- 打开文件之后就会设置流状态
- 对应于这个标志字各状态位,ios类还提供了以下成员函数来检测或设置流的状态:
bool rdstate(); //返回流的当前状态标志字
bool eof(); //返回非0值表示到达文件尾
bool fail(); //返回非0值表示操作失败
bool bad(); //返回非0值表示出现错误,物理上产生致命错误
bool good(); //返回非0值表示流操作正常
bool clear(int flag=0); //将流的状态设置为flag,清除流状态,如果流出现失败,但又想继续使用流的话,就先清除
- eg:P59\05.cpp
#include <cassert>
#include <iostream>
#include <fstream>
using namespace std;
int main(void)
{
// app 与 trunc 不能共存,流状态为fail
ofstream fout3( "test.txt", ios::out | ios::app | ios::trunc);
if (fout3.good())
{
cout << "good" << endl;
}
if (fout3.bad())
{
cout << "bad" << endl;
}
if (fout3.fail())
{
cout << "fail" << endl;
}
if (fout3.eof())
{
cout << "eof" << endl;
}
//如果出现bad错误,流不能继续使用了
//流状态出现错误,但是还想继续使用,需要clear
fout3.clear();
fout3.open( "test.txt"); // clear之后能够重新open
if (fout3)
{
cout << "open succ" << endl;
}
else
cout << "open failed" << endl;
fout3.close();
return 0;
}
5.文件关闭
- 每个文件流类中都提供有一个关闭文件的成员函数close()
功能:当打开的文件操作结束后,就需要关闭它,使文件流与对应的物理文件断开联系,并能够保证最后输出到文件缓冲区中的内容,无论是否已满,都将立即写入到对应的物理文件中(磁盘上)
函数原型:void close();
- 文件流对应的文件被关闭后,还可以利用该文件流调用open成员函数打开其他的文件,最好先clear 一下。
- 参考:从零开始学C++之IO流类库(二):文件流(fstream, ifstream, ofstream)的打开关闭、流状态,从零开始学C++之IO流类库(二):文件流(fstream, ifstream, ofstream)的打开关闭、流状态