在C++中是通过流来进行I/O操作的。ostream是从内存到硬盘,istream是从硬盘到内存,所谓的流缓冲就是内存空间。stream提供了2个重要的操作符:
- 插入符(<<) 向流输出数据,对于默认的标准输出流cout,指的是输出到屏幕。
- 析取符(>>) 从流中输入数据,对于默认的标准输入流cin,指的是键盘。
C++中输出和输入到屏幕和键盘的类生命包含在<iostream>头文件中,磁盘内文件的I/O声明在头文件<fstream>中。以下是I/O类的继承关系。
fstream提供3个类,实现对文件的操作。
ifstream --从已有的文件读
ofsream --向文件写内容
fsream --打开文件供读写
下面一一介绍其具体操作。
一. 打开文件
在fstream中有一个成员函数open()可以用来打开文件,其原型是:void open(const char* filename, int mode, int access);
其中filename是要打开的文件名; mode是打开文件的方式; access是打开文件的属性。
打开文件的方式是在类ios中定义的,有如下的值:
ios::in : 为输入(读)而打开文件
ios::out 为输出(写)而打开文件
ios::ate 定位到文件尾
ios::app : 以追加的方式打开文件
ios::trunc 如果文件已经存在,则先删除该文件
ios::binary 以二进制方式处理文件
ios::nocreate 不建立文件,所以文件不存在则打开失败
ios::noreplace 不覆盖文件,如文件已经存在,则失败
可以用 | 将各个属性链接起来,表示或。
打开文件的属性取值:
0 :普通文件,打开访问; 1 :只读文件; 2: 隐含文件; 3: 只读和隐含; 4: 系统文件
可以用“或”或者“+”将以上属性连接起来。
例如打开读取文件/home/del.txt, 可以用以下方式:
fstream file1;
file1.open("/home/del.txt", ios:in, 0);
或者在定义类的时候直接打开,因为fstream的构造函数的第一个参数是文件名。
open函数只有一个参数的话,则是以读/写普通文件的方式打开。
对于fstream的子类,ifsream默认以输入方式打开文件,ofstream默认是以输出方式打开文件。
打开文件之后一定要将其关闭,fstream提供了成员函数close()来完成此操作,如file1.close(),就是把file1相连的文件关闭。
二. 读写文件
读写文件分为文本文件和二进制文件的读取,文本文件的读取使用插入符和析取符即可;而二进制相对较复杂。
1. 文本文件用<<表示向文件输出,用>>表示从文件输入。如file1<<"this is the way\n".
这种方法提供了简单的格式化的功能。dec:表示格式化为10进制数值数据;endl:表示输出一个换行符,并刷新此流;hex/oct: 格式化为16/8进制的数据;setprecision(int n):设置浮点数夫人精度位数。
例如:file1 << setprecision(5) << 3.1415926.
2. 二进制文件的读写
⑴ put() 函数向流写入一个字符,其原型是 ofstream& put(char ch), 如file.put(‘c‘)表示向流写入一个字符。
(2) get()函数比较灵活,有3种重载形式:
ifstream& get(char
&ch):功能是从流中读取一个字符,结果保存在引用中,如果到文件尾,返回空字符。如file1。get(x),表示从流中读取一个字符,并把读取的字符保存在x中。
另一种是int get(); 从流中返回一个字符,达到文件尾,返回EOF, 如x=file1.get()
还有一种其原型是:ifstream& get(char* buf, int num, char delim = ‘\n‘);把字符读入由buf指向的数组,直到读入了num个字符,或遇到了由delim制定的字符。若未使用delim 参数,则将使用缺省值换行符。如file2.get(str1,127,‘a‘);//从文件中读取字符到字符串str1,当遇到字符‘a‘或读取了127个字符时终止。
(3)读写数据块 要读写二进制数据块,使用成员函数read()和write(),其原型如下:
read(unsogned char buf, int num); write(const unsigned char buf, int num);
rand()从文件中读取num个字符到buf指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是 unsigned char *,有时可能需要类型转换。如:
unsigned char str1[]="I Love You"; int n[5]; ifstream in("xxx.xxx"); ofstream out("yyy.yyy"); out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中 in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换 in.close();out.close();
3. 检测EOF 成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof();
例: if(in.eof()) ShowMessage("已经到达文件尾!");
三. 文件定位
和C的文件操作方式不同的是,C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时, 相应的指针自动变化。所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是seekg()和seekp()。seekg()是设置读位置, seekp是设置写位置。它们最通用的形式如下:
istream &seekg(streamoff offset,seek_dir origin); ostream &seekp(streamoff offset,seek_dir origin);
streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举:
ios::beg: 文件开头 ios::cur: 文件当前位置 ios::end: 文件结尾
这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。例:
file1.seekg(1234,ios::cur); //把文件的读指针从当前位置向后移1234个字节 file2.seekp(1234,ios::beg); //把文件的写指针从文件开头向后移1234个字节
大量内容来自https://www.byvoid.com/blog/cpp-fstream,特此说明。