一、基础点
1、文件操作类
fstream: 可同时读写操作的文件类(由iostream引申而来)
ofstream: 写操作(输出)的文件类(由ostream引申而来)
ifstream: 读文件(输入)的文件类(由istream引申而来)
(文件类的实质,解释的很好)
对这些类的一个对象所做的第一个操作通常就是将它和一个真正的文件联系起来,也就是说打开一个文件。被打开的文件在程序中由一个流对象(stream object)来表示(这些类的实例),而这个流对象所做的任何输入输出操作实际上就是对该文件所做的操作。
2、打开文件:
(1)使用流对象的open()函数打开文件,默认以写方式打开文件时,文件不存在则创建,而以读打开时不存在则打开不成功。文件打开时默认是以兼容共享模式。如:
mode是以下标志符的一个组合:void open (const char * filename, openmode mode);
文件打开方式选项 | |
ios::in = 0x01 | 为输入(读)而打开文件 |
ios::out = 0x02 | 为输出(而)而打开文件 |
ios::ate = 0x04 | 初始位置:文件尾,但是以输出方式打开时,也是存在文件则先删除。 |
ios::app = 0x08 | 所有输出附加在文件末尾,即使定位指针也是附加在文件末尾。 |
ios::trunc = 0x10 | 如果文件已存在则先删除该文件 |
ios::binar = 0x80 | 二进制方式 |
文件保护方式选项 | 用在缓存文件中 |
filebuf::openprot | 默认的兼容共享方式 |
filebuf::sh_none | 独占,不共享 |
filebuf::sh_read | 读共享 |
filebuf::sh_write | 写共享 |
这些标志符可以被组合使用,中间以“或”操作符“|”间隔。例如,我们想以二进制方式打开文件“example.bin”来写入一些数据,我们可以通过以下方式调用成员函数open()来实现
ofstream file;file.open("example.bin", ios::out | ios::app | ios::binary);
ofstream, ifstream和fstream所有这些类的成员函数open都包含了一个默认打开文件的方式,这三个类的默认方式各不相同:
类 | 参数的默认方式 |
fstream | ios::in | ios::out |
ifstream | ios::in |
ofstream | ios::out | ios::trunc |
只有当函数被调用而没有声明mode的情况下,默认值才会被采用。如果函数调用时声明了任何参数,默认值将被完全改写,而不会与调用参数组合。(自己应该养成声明mode的习惯)
(2)构造函数打开文件
对上面打开文件example.bin文件的方式改写
ofstream file ("example.bin", ios::out | ios::app | ios::binary);
两种打开文件的方式都是正确的。
(3)检测打开是否成功
使用“is_open()”成员函数来检测是否顺利打开,它返回一个bool值,“true”代表顺利打开,“false”代表打开失败。
3、关闭文件
当文件读写完成之后,必须将文件关闭以使其重新变为可访问的。关闭文件需要调用“close()”函数,它负责将缓存中数据释放出来并关闭文件。
这个函数一旦调用,原先的流对象就可以被用来打开其他的文件了,打开其他文件时,一定要先用clear()函数来将流对象的指针等标志位数据重新初始化。
如果文件不存在时,这时候不止调用open会出错,调用close也会出错。
为了防止流对象被销毁时还联系着打开的文件,析构函数(destructor)将会自动调用关闭函数close()。
4、读写文件
(1)文本文件(Text mode files)
类ofstream, ifstream和fstream分别从ostream,istream和iostream中引申而来,这就是为什么fstream的对象可以使用其父类的成员来访问数据。
我们使用重载的“<<”和“>>”来“输入”和“输出”,如
// writing on a text file file example.txt
#include <fiostream.h>int main () {ofstream examplefile ("example.txt");
if (examplefile.is_open()) {
examplefile << "This is a line.\n"; // 写入文件时,如果定位了指针,默认是覆盖已有的文件内容,
// 而不会将已有的内容后移。
examplefile << "This is another line.\n";
examplefile.close();}return 0;
}
(2)二进制文件(未完待续)
5、检测EOF
成员函数eof()用来检测是否到达文件尾:
到达文件尾 | 返回非0值 |
未到达文件尾 | 返回0 |
6、获取和设置流指针(get and put stream pointers)
所有的输入/输出流对象都至少有一个流指针:
ifstream | get pointer,指向下一个将被读取的元素 |
ofstream | put pointer,指向下一个将写入的位置 |
fstream | 同时继承get和put |
我们可以使用以下成员函数来读出和配置这些指向流中读写位置的流指针:
streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值
ifstream | |
tellg() | 返回pos_type类型的值,根据(ANSI-C++标准),是一个整数,代表当前的指针位置 |
seekg ( off_type offset, seekdir direction ) | 根据direction的初始位置移动offset个位置 |
ofstream | |
tellp() | 同tellg() |
seekp ( off_type offset, seekdir direction ); | 同seekg |
direction的值可以是以下三种中的一个:
ios::beg | 从流开始的位置 |
ios::cur | 从流指针当前的位置 |
ios::end | 从流末尾的位置 |
由于文本文件中某些特殊字符可能被修改,所有这些函数一般用于二进制文件中。
二、自己在使用过程中的总结:
1、在从ascii文件输入时,每一个空格会中止文件的读取。
2、文件读取
可以采用定义数据类型,然后用“>>”操作符来读取。如读取一个浮点数:
float number;
in>>number;
要注意的是,不可以忽略任意定义的长度,因为在ascii文件中,浮点数的表示长度是不定的,是采取对浮点数每一个字符的编码来完成的,如12.55,就是采用”1“,”2“,”.“,”5“,”5“来存储的,如果小数点后位数很多,那么占用的空间也会相应加大。
用一个文件变量操作多个文件时,一定要记得在关闭文件后调用clear()函数。如果一个文件打开不成功的情况下,再调用close()函数,也会出错的。这时候就应该先关闭,再clear(),这样就把close的错误给清空了。
3、写入文件
写入文件要以追加的方式打开文件,追加的方式打开文件时会自动将指针定位到文件尾。如:
ofstream out;
out.open("c:\\haha.txt",ios::app);
这样才行,否则的话原来的文件内容都会丢失。
但是这种方式有一个坏处,就是即使你定位了文件指针,输出还是附加到文件末尾。
4、写入文件
文件在写入时,如果定位了文件指针,而且当前文件指针的地方已经有文件内容,那么在写入的时候会覆盖掉当前的文件内容。而不会感性的会将文件内容后移。
5、写入文件
文件写入后,一定要关闭文件。因为文件写入时,是先写入到系统的数据中流中,然后流数据积累到一定大小后便可以输出到文件中,而关闭文件操作即是立即将流中的数据写入到文件中去。