一、文件输入输出类简述
在头文件fstream中声明了如下类:
basic_filebuf basic_ofstream basic_ifstream basic_fstream
这些类提供了文件输入和输出的高层接口,其中的basic_filebuf提供了对文件的缓冲访问
1.1 basic_ofstream
basic_ofstream是从basic_ostream派生而来的模板类,包含了将输出文件和basic_ofstream流关联起来的构造函数和成员函数。basic_ofstream从basic_ostream继承了在 输出流中写入数据和在输出流中进行移动的成员函数。
可定义如下形式的构造函数
explicit basic_ofstream(const char* filename, ios_base::openmode mode = ios_base::out)
将一个basic_ofstream对象以mode模式打开的文件filename相关联。类型openmode是一个bitmask类型。
ofstream的构造函数 basic_ofstream(const char* filename) 其默认的文件打开模式是输出方式。
在ofstream类中,iso_base::out是指定和默认的打开模式,如果指定了其他打开模式,该模式将与iso_base::out一起应用到这个文件。如果文件不能打开,则设置failbit标志。
1.2 basic_ifstream
basic_ifstream是从basic_istream派生而来的模板类,包含了将输入文件和basic_ifstream流关联起来的构造函数和成员函数。basic_ifstream从basic_istream继承了读取输入流数据及在输入流中进行移动的成员函数。
可定义如下形式的构造函数
explicit basic_ifstream(const char* filename, ios_base::openmode mode = ios_base::in)
ifstream的构造函数 basic_ifstream(const char* filename) 其默认的文件打开模式是输入方式。
在ifstream类中,iso_base::in是指定和默认的打开模式,如果指定了其他打开模式,该模式将与iso_base::in一起应用到这个文件。如果文件不能打开,则设置failbit标志。
1.3 basic_fstream
basic_fstream是从basic_iostream派生而来的模板类,包含了将输入文件和basic_fstream流关联起来的构造函数和成员函数。basic_fstream从basic_iostream继承了读写文件数据及在文件中移动的成员函数。
可定义如下形式的构造函数
explicit basic_fstream(const char* filename, ios_base::openmode mode = ios_base::in | ios_base::out)
fstream的构造函数 basic_fstream(const char* filename) 其默认的文件打开模式是输入/输出方式。
二、打开文件
在ifstream,ofstream,fstream类中都有一个成员函数open,可用于打开文件,函数原型为
void open(const char* filename, int mode)
其中 filename 指的是文件名, mode是要打开文件的方式
打开文件的方式在类ios(是所有流式I/O类的基类)中定义,常用的值如下:
ios::app : 以追加的方式打开文件
ios::ate : 文件打开后定位到文件尾,ios::app就包含有此属性
ios::binary : 以二进制方式打开文件,缺省的方式是文本方式。
ios::in : 文件以输入方式打开
ios::out : 文件以输出方式打开
ios::nocreate : 不建立文件,所以文件不存在时打开失败
ios::noreplace : 不覆盖文件,所以打开文件时如果文件存在失败
ios::trunc : 如果文件存在,把文件长度设为0
对于以上打开方式,可用 “ | ” 把上面打开方式连接起来,如一追加,输出及二进制方式打开文件,可表示为 ios::app|ios::out|ios::binary
//******************注意
网络上查到的很多关于open函数的原型是
void open(const char* filename, int mode, int access);
在这里参数filename,mode和上面所述一样,access指的是 打开属性
打开文件的属性取值可以是:
0 : 普通文件,打开访问
1 : 只读文件
2 : 隐含文件
4 :系统文件
可以用 " | " 或是 “ + ” 将上面属性连起来
但我在实际编写中发现,在gcc4.4.3版本下,open函数原型是不包括access参数的,所以也就是说执行函数open(filename,mode,access)会报错,而正确执行是open(filename,mode)。另外对于mode,也发现iso::nocreate是不存在的。大概这些改动对于更高版本的gcc也是成立的吧。网上的很多资料大概也是相对较老版本所撰写的。所以在执行函数时有必要注意这两种情况。
*************************************************************************//
三、文件关闭
每次执行文件操作时,文件打开后都需要执行文件关闭操作。文件关闭的函数原型为
void close();
虽然在进程结束时,文件会被自动关闭。但系统能够打开的文件数及进程能够打开的文件数是有限的,关闭文件句柄时,会将输出缓冲区的内容刷新到文件中,如果进程意外结束,可能会造成输出缓冲区的内容丢失从而造成文件内容的丢失,所以在文件操作完成时,应养成习惯关闭文件。
四、读写文件
文件读写分为文本文件读写和二进制文件读写。
1.文本文件读写
文本文件读写可直接用插入器(<<)向文件输出,用析取器(>>)从文件输入
如下代码展示向file1输入“test”,从file2读入一个整数
#include <iostream>
#include <fstream>
using namespace std;
int main(){
fstream file1, file2;
file1.open("file1",ios::out);
file2.open("file2",ios::in);
file1<<"test";
int i;
file2>>i;
}
2.二进制文件读写
①put()
put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。
②get()
get()函数比较灵活,有3种常用的重载形式:
一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。
另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。
还有一种形式的原型是:ifstream &get(char *buf,int num,chardelim='\n');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用delim 这个参数,将使用缺省值换行符'\n'。例如:
file2.get(str1,127,'A');//从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。
③读写数据块
要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:
read(unsigned char *buf,int num);
write(const unsigned char *buf,int num);
read()从文件中读取 num 个字符到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 intgcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是unsigned char *,有时可能需要类型转换。
class RLETriples{
private:
int num;
int position;
int length;
public:
RLETriples();
RLETriples(int n, int p, int l);
int getNum();
int getPosition();
int getLength();
};
RLETriples::RLETriples(){
num = 0;
position = 0;
length =0;
}
RLETriples::RLETriples(int n, int p, int l){
num = n;
position = p;
length = l;
}
int main(){
RLETriples triples1(1, 0, 4);
RLETriples triples2(2, 4, 5);
fstream fout, fin;
fout.open("out", ios::app|ios::out|ios::binary);
fout.write((char*)(&triples1), sizeof(triples1));
fout.write((char*)(&triples2), sizeof(triples2));
fout.close();
RLETriples getTriples;
fin.open("out", ios::in|ios::binary);
fin.read((char*)(&getTriples),sizeof(getTriples));
fin.close();
}
五、关于EOF/eof
成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof();
关于eof()函数的问题可以查看这里:http://blog.youkuaiyun.com/pear_zi/article/details/6917268
另外,大写的EOF和小写的eof是不一样的。
如上面说的,小写的eof是文件输入输出类中判断文件是否结束的函数。
而大写的EOF,在C标准函式库中表示:文件结束符(End of File).他是一个宏定义的数值,为-1。这里要强调一点就是,这种以EOF作为文件结束标志的文件,必须是文本文件。在文本文件中,数据都是以字符的ASCII代码值的形式存放。我们知道,ASCII代码值的范围是0~255,不可能出现-1,因此可以用EOF作为文件结束标志。