您的位置:首页 > 编程语言 > C语言/C++

C++文件读取操作详解

2016-07-25 20:30 316 查看


C++文件读取操作详解

http://blog.csdn.net/blues1021。




图片来自:http://www.cplusplus.com/reference/iolibrary/
上面的C++ IO类继承关系图,这里的箭头不是子类指向父类的继承,而是指父类派生子类的方向。这里主要描述ifstream类/oftream类/fstream类的使用细节和这些类的系统内部同步缓存机制。


一、文件打开的方式和默认选项


// 附加到末尾,原来的数据不变
ios::app Opens an output file for appending.
// 文件打开后定位到文件尾,ios:app就包含有此属性
ios::ate Opens an existing file (either input or output) and seeks the end.//附加到末尾原来的数据会被清空(单独或与out组合),当与in或app组合时候会附加到末尾。
ios::in Opens an input file. Use ios::in as an open_mode for an ofstream file to prevent truncating an existing file.  
ios::out Opens an output file. When you use ios::out for an ofstream object without ios::app, ios::ate, or ios::in, ios::trunc is implied.
ios::nocreate Opens a file only if it already exists; otherwise the operation fails.
ios::noreplace Opens a file only if it does not exist; otherwise the operation fails.
ios::trunc Opens a file and deletes the old file (if it already exists).
ios::binary Opens a file in binary mode (default is text mode).

fstream默认是以ios::in|ios::out方式打开文件。
ifstream默认是以ios::in方式打开文件。
ofstream默认是以ios::out|ios::trunc方式打开文件,所以oftream一不小心就会覆盖掉之前的文件。

二、文件流对象打开文件(及内核缓存)和关闭文件[b](及内核缓存)[/b]

fstream有两个子类:ifstream(input file stream)和ofstream(outpu file stream)。ifstream默认以输入方式打开文件,而ofstream默认以输出方式打开文件。 
三个类可以用open打开文件,close关闭文件;且构造函数中都封装了open方法,析构函数中封装了close方法。
1)构造析构方式:如果文件流对象只是函数内操作一个文件的临时对象,那么可以用构造函数打开,临时对象生命期到的时候会自动调用 
析构函数释放文件句柄和关联的内核读写缓存。
2)open/close方式:如果文件流对象是一个类数据成员或者操作多个文件,那么需要用open打开文件,用close关闭文件,关闭了以后就可以打开另一个文件。

三、C++文件操作常用函数:

1)通用的函数:
void open(const char* filename,int mode,int access); 
打开文件的属性取值是: 
0:普通文件,打开访问  1:只读文件  2:隐含文件  4:系统文件  
可以用“或”或者“+”把以上属性连接起来 ,如3或1|2就是以只读和隐含属性打开文件。
fstream file1;  
file1.open("c:config.sys",ios::binary|ios::in,0);

is_open判断是否打开成功的函数。

2)流状态检测函数:
eof()是否结束的判断。
bad()函数,如果在读写过程中出错,返回 true。
例如:当我们要对一个不是打开为写状态的文件进行写入时,或者我们要写入的设备没有剩余空间的时候。
fail()函数,除了与bad() 同样的情况下会返回 true 以外,加上格式错误时也返回true ,例如当想要读入一个整数,而获得了一个字母的时候。
good()判断流是否是好的,比如经常用到的标准输入cin,要读入一个int型的数据时,却读到了一个char,这是cin.good()就返回false,表示输入流出错了。
clear()函数重置以上成员函数所检查的状态标志。

3)流指针相关函数
所有输入/输出流对象(i/o streams objects)都有至少一个流指针,流指针相关函数:
含有g的函数是input ifstream中的获取操作流指针位置的函数,含有p的函数是output stream中获取操作文件流指针的函数。

tellg() 和 tellp()  
这两个成员函数不用传入参数,返回pos_type 类型的值(根据ANSI-C++ 标准) ,就是一个整数,代表当前get流指针的位置(用tellg)
或put流指针的位置(用tellp)。

seekg() 和seekp()  
这对函数分别用来改变流指针get 和put的位置。两个函数都被重载为两种不同的原型: 
seekg ( pos_type position ); seekp ( pos_type position );  
使用这个原型,流指针被改变为指向从文件开始计算的一个绝对位置。
要求传入的参数类型与函数 tellg 和tellp 的返回值类型相同。 
seekg ( off_type offset, seekdir direction ); 
seekp ( off_type offset, seekdir direction );  
使用这个原型可以指定由参数direction决定的一个具体的指针开始计算的一个位移(offset)。它可以是:
ios::beg, ios::cur, ios::end。

文本文件对文件流指针不能使用seekp因为文本文件的某些特殊字符可能会被修改,可以使用seekg;文本文件不要对tellg,tellp返回的指针进行修改。
二进制文件,可以随便的使用tellg,tellp,seekg,seekp函数来获取和修改流指针位置。

四、文件文件读写方式
文本文件读取:
<<输出重载运算符,>>输入重载运算符。
getline获取一行

操纵符 功能 输入/输出  
dec 格式化为十进制数值数据 输入和输出  
endl 输出一个换行符并刷新此流 输出  
ends 输出一个空字符 输出  
hex 格式化为十六进制数值数据 输入和输出  
oct 格式化为八进制数值数据 输入和输出 
 setpxecision(int p) 设置浮点数的精度位数 输出 
比如要把123当作十六进制输出:file1<<hex<<123;要把3.1415926以5位精度输出:file1<<setpxecision(5)<<3.1415926。
文本方式读入二进制文件会失败,读取文件文件会将"\r\n"翻译为"\n"后输出。

五、二进制文件读写方式
在二进制文件中,使用<< 和>>,以及函数(如getline)来操作符输入和输出数据,没有什么实际意义,虽然它们是符合语法的。
put()函数
get()函数。

块状读取函数:
文件流包括两个为顺序读写数据特殊设计的成员函数:write 和 read。
第一个函数 (write) 是ostream 的一个成员函数,都是被ofstream所继承。
而read 是istream 的一个成员函数,被ifstream 所继承。
类 fstream 的对象同时拥有这两个函数。它们的原型是: 
write ( char * buffer, streamsize size ); 
read ( char * buffer, streamsize size );  
这里 buffer 是一块内存的地址,用来存储或读出数据。参数size 是一个整数值,表示要从缓存(buffer)中读出或写入的字符数。
二进制读写文件可以节省内存和提高速度,二进制方式读取二进制文件是内存中一样的数据,二进制读取文本文件"\r\n"不会被翻译为"\n",故二进制读取的文件都是原始不经任何翻译改变的数据。

六、缓存和同步(Buffers and Synchronization)
C++中缓冲区的刷新机制:

当我们对文件流进行操作的时候,它们与一个streambuf 类型的缓存(buffer)联系在一起。这个缓存(buffer)实际是一块内存空间,
作为流(stream)和物理文件的媒介。例如,对于一个输出流, 每次成员函数put (写一个单个字符)被调用,
这个字符不是直接被写入该输出流所对应的物理文件中的,而是首先被插入到该流的缓存(buffer)中。 
当缓存被排放出来(flush)时,它里面的所有数据或者被写入物理媒质中(如果是一个输出流的话),
或者简单的被抹掉(如果是一个输入流的话)。这个过程称为同步(synchronization),它会在以下任一情况下发生:

1)当文件被关闭时: 在文件被关闭之前,所有还没有被完全写出或读取的缓存都将被同步。   
2)当缓存buffer 满时:缓存Buffers 有一定的空间限制。当缓存满时,它会被自动同步。   
3)控制符明确指明:当遇到流中某些特定的控制符时,同步会发生。这些控制符包括:flush 和endl。   
4)明确调用函数sync(): 调用成员函数sync() (无参数)可以引发立即同步。
这个函数返回一个int 值,等于-1 表示流没有联系的缓存或操作失败。

C语言中下列情况会引发缓冲区的刷新:
1)缓冲区满时;
2)行缓冲区遇到回车时;
3)关闭文件;
4)使用特定函数刷新缓冲区。

清除和设置文件缓冲区

(1).清除文件缓冲区函数: int fflush(FILE *stream); int flushall();
fflush()函数将清除由stream指向的文件缓冲区里的内容,常用于写完一些数据后,立即用该函数清除缓冲区,以免误操作时,
破坏原来的数据。 flushall()将清除所有打开文件所对应的文件缓冲区。

(2).设置文件缓冲区函数 void setbuf(FILE *stream,char *buf); void setvbuf(FILE *stream,char *buf,int type,unsigned size);
这两个函数将使得打开文件后,用户可建立自己的文件缓冲区,而不使用fopen()函数打开文件设定的默认缓冲区。
对于setbuf()函数,buf指出的缓冲区长度由头文件stdio.h中定义的宏BUFSIZE的值决定,缺省值为512字节。
当选定buf为空时,setbuf函数将使的文件I/O不带缓冲。而对setvbuf函数,则由malloc函数来分配缓冲区。
参数size指明了缓冲区的长度(必须大于0),而参数type则表示了缓冲的类型,其值可以取如下值: type 值 含义 _IOFBF 文件全部缓冲,
即缓冲区装满后,才能对文件读写 _IOLBF 文件行缓冲,即缓冲区接收到一个换行符时,才能对文件读写 _IONBF 文件不缓冲,
此时忽略buf,size的值,直接读写文件,不再经过文件缓冲区缓冲。

buf是自己申请的静态内存空间或者malloc出来的内存空间,设置进去。

使用注意:
1) 不管是C++还是C都存在读写缓存,平时默认缓存文件的读写,fread/fwrite等其实都是对默认缓存内存的读写,默认缓存的大小是512kb。
2)读写缓存的目的是为了提高整体的读写效率,如果一些数据需要马上刷新到磁盘,可以调用刷新flush/fflush或同步函数。也可以取消同步std::ios::sync_with_stdio(false)。
*/
#include "stdafx.h"
#include <fstream>
using namespace std;
#include "CPPFILE_OPR.h"

void CppFileOperate::process()
{
 ofstream ofile("f:\\test.txt",ios::ate | ios::in);
 ofile.open(ios_base::_Openprot)
 if(ofile.is_open())
 {
  ofile<<"456"<<endl;
  ofile.close();
 }
 ofile.eof();
 FILE
 //while(1);
}
参考:
http://wenku.baidu.com/view/85ece92dbd64783e09122b56.html

更多的细节参考标准文档:
http://www.cplusplus.com/reference/iolibrary/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息