以下是c++标准中的文件操作方法。
c++的文件操作需要用到下面这三个类
- ofstream: 写操作(输出)的文件类 (由ostream继承而来)
- ifstream: 读操作(输入)的文件类(由istream继承而来)
- fstream: 可同时读写操作的文件类 (由iostream继承而来)
从上图是各个类的继承关系,fstream是iostream的子类
Node:
- 确保include<fstream>
- 在名称空间std下
#open,close#
有两个两个函数非常重要。open函数会通知操作系统我们要读写某个文件了。这样别的程序就不能再改写这这文件了。避免了文件读写时的错乱。close函数会告诉操作系统,文件操作可以结束了。别的程序可以操作这个文件了。同时也可以去操作别的文件了
**open **
void open (const char * filename, openmode mode);
第一个参数,是我们想要打开的文件路径
第二个参数未打开方式的一组组合(通过|)
- ios::out 为输出(写)而打开文件
- ios::ate 初始位置:文件尾
- ios::app 所有输出附加在文件末尾
- ios::trunc 如果文件已存在则先删除该文件
- ios::binary 二进制方式
该参数在不同的文件对象中是有缺省值的
- ofstream对象为 ios::out | ios::trunc
- ifstream 对象为ios::in
- fstream 对象为ios::in | ios::out
close
void close ();
Node:
opne 方法已经整合到构造函数中了。我们可以只需要调用相应参数的构造函数就可以不用调用open函数了.其实open在visual c++还有第三个参数,负责说明文件保护方式,因为不是c++标准,所以我们也不知道干什么的
close 已经整合到析构函数中了,所以我们其实也可以不用直接调用
#文本操作#
对于文本方面的操作,我们可以像在控制台上操作一样使用重载了的操作符号**<<和>>**和对应的一些读写操作的函数如get,getline,put。
写
//#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<fstream>
using namespace std;
int main() {
ofstream of("lean.text");
if (of.is_open()) {
of << "I'm wen";
of.close();
}
return 0;
}
读
//#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<fstream>
using namespace std;
int main() {
char buffer[256];
ifstream inputf("lean.text");
if (!inputf.is_open()){
cout << "Error" << endl;
exit(1);
}
//下面会用到一些特殊标识,下面会说
while (!inputf.eof()) {
inputf.getline(buffer, 100);
cout << buffer << endl;
}
cin.get();
return 0;
}
##相关标志##
上图是我在cplusplus上找的可以很好的说明相关函数的作用和返回值
Node:
当出现上述标志时,可以使用clear()函数来重置标志。
#二进制文件#
对二进制文件操作之前我们要在open第二个参数设置为ios::binary.这样fstream就会用二进制来处理文件了。
对于二进制文件,如果我们可以像处理文本一样,使用>>,<<或者getline函数。但是通常这些是无意义的。所以我们用到了另两函数
write ( char * buffer, streamsize size );
read ( char * buffer, streamsize size );
他们会分别读取(写入)流中一段的数据,很适合处理二进制流。那么问题来了我们怎么定位数据段呢?就要说一说流指针了
#流指针(get and put stream pointers)#
流指针,get pointer指针指向下一个将被读取的元素。 put pointer指针指向写入下一个元素的位置。
tellg() 和 tellp()
这两个成员函数不用传入参数,返回pos_type 类型的值(根据ANSI-C++ 标准) ,就是一个整数,代表当前get 流指针的位置 (用tellg) 或 put 流指针的位置(用tellp).
seekg() 和seekp()
这对函数分别用来改变流指针get 和put的位置。原型如下
//使用这个原型,流指针被改变为指向从文件开始计算的一个绝对位置。要求传入的参数类型与函数 tellg 和tellp 的返回值类型相同。
seekg ( pos_type position );
seekp ( pos_type position );
//使用这个原型可以指定由参数direction决定的一个具体的指针开始计算的一个位移(offset)。:
seekg ( off_type offset, seekdir direction );
seekp ( off_type offset, seekdir direction );
seekdir
- ios::beg 从流开始位置计算的位移
- ios::cur 从流指针当前位置开始计算的位移
- ios::end 从流末尾处开始计算的位移
Node:
流指针 get 和 put 的值对文本文件(text file)和二进制文件(binary file)的计算方法都是不同的,因为文本模式的文件中某些特殊字符可能被修改。由于这个原因,建议对以文本文件模式打开的文件总是使用seekg 和 seekp的第一种原型,而且不要对tellg 或 tellp 的返回值进行修改。对二进制文件,你可以任意使用这些函数,应该不会有任何意外的行为产生。
下面代码会读取文件大小
#include<iostream>
#include<fstream>
using namespace std;
int main() {
long l, m;
ifstream inputf("..\\Debug\\c++iostream.exe", ios::in | ios::binary);
l = inputf.tellg();
inputf.seekg(0, ios::end);
m = inputf.tellg();
inputf.close();
cout << "size of " << "c++iostream.exe";
cout << " is " << (m - l) << " byte.\n";
system("PAUSE");
return 0;
}
#缓存和同步(Buffers and Synchronization)#
当我们对文件流进行操作的时候,它们与一个streambuf 类型的缓存(buffer)联系在一起。这个缓存(buffer)实际是一块内存空间,作为流(stream)和物理文件的媒介。例如,对于一个输出流, 每次成员函数put (写一个单个字符)被调用,这个字符不是直接被写入该输出流所对应的物理文件中的,而是首先被插入到该流的缓存(buffer)中。
当缓存被排放出来(flush)时,它里面的所有数据或者被写入物理媒质中(如果是一个输出流的话),或者简单的被抹掉(如果是一个输入流的话)。这个过程称为同步(synchronization),它会在以下任一情况下发生:
- 当文件被关闭时: 在文件被关闭之前,所有还没有被完全写出或读取的缓存都将被同步。
- 当缓存buffer 满时:缓存Buffers 有一定的空间限制。当缓存满时,它会被自动同步。
- 控制符明确指明:当遇到流中某些特定的控制符时,同步会发生。这些控制符包括:flush 和endl。
Node:
明确调用函数sync(): 调用成员函数sync() (无参数)可以引发立即同步。这个函数返回一个int 值,等于-1 表示流没有联系的缓存或操作失败