- 1. C的IO流
- 1.1 数据流
- 1.2 缓冲区
- 1.3 文件类型
- 1.4 文件存取方式
- 1.5 借助文件指针读写文件
- 1.6 操作流程图
- 2. C++ 文件IO流
- 2.1 文件流类与文件流对象
- 2.2 文件的打开和关闭
- 2.2.1 定义流对象
- 2.2.2 打开文件
- 2.2.3 文件的关闭
- 2.4 流文件状态与判断
- 2.4.1 标识位
- 2.4.2 函数
- 2.5 文件的读写操作
- 2.5.1 读写文本文件
- 2.5.2 读写二进制文件
- 3. (cin)和(!cin)的原理
指程序与数据的交互是以流的形式进行的。进行 C 语言文件的存取时, 都会先进行“打开文件”操作,这个操作就是在打开数据流,而“关闭文件”操作就是关闭数据流。1.2 缓冲区
指在程序执行时,所提供的额外内存,可用来暂时存放做准备执行的数据。它的设置是为了提高存取效率,因为内存的存取速度比磁盘驱动器快得多。
C++ 语言中带缓冲区的文件处理:
C++ 语言的文件处理功能依据系统是否设置“缓冲区”分为两种:一种是设置缓冲区,另一种是不设置缓冲区。当使用标准 I/O 函数(包含在头文件 cstdio 中)时,系统会自动设置缓冲区,并通过数据流来读写文件。 当进行文件读取时,不会直接对磁盘进行读取,而是先打开数据流,将磁盘上的文件信息拷贝到缓冲区内,然后程序再从缓冲区中读取所需数据,如下图所示:
分为文本文件和二进制文件两种。
文本文件:
是以字符编码的方式进行保存的,只是计算机以二进制表示数据在外部存储介质上的另一种存放形式。它所存放的每一个字节都可以转换为一个可读字符。当向文件中写入数据时,windows 中一旦遇到"换行"字符(ASCII 码为 10)则会转换成"回车-换行"(ASCII 值为 13,10)。在读取数据的时候,一遇到"回车-换行"的组合 ASCII 值为 13,10),则会转换成为"换行"字符(ASCII 码为 10)。
二进制文件:
将内存中数据原封不动的读取和写入文件中。二进制文件适用于非字符为主的数据。如果以记事本打开,只会看到一堆乱码。除了文本文件外,所有的数据都可以算是二进制文件。二进制文件的优点在于存取速度快,占用空间小,以及可随机存取数据。
包括顺序存取方式和随机存取方式两种。
顺序读取:
也就是从上往下,一笔一笔读取文件的内容。保存数据时,将数据附加在文件的末尾。这种存取方式常用于文本文件,而被存取的文件则称为顺序文件。
随机存取:
多半以二进制文件为主.它会以一个完整的单位来进行数据的读取和写入,通常以结构为单位。
如果要访问文件,要借助于文本变量,即文件指针 FILE *才可以完成。文件在进行读写操作之前要先打开,使用完毕要关闭。所谓打开文件,实际上是建立文件的各种有关信息,并使文件指针指向该文件,以便进行其它操作。关闭文件则断开指针与文件之间的联系,也就禁止再对该文件进行操作。
1.6 操作流程图 2. C++ 文件IO流 2.1 文件流类与文件流对象对文件的操作是由文件流类完成的。文件流类在流与文件间建立连接。由于文件流分为三种:文件输入流、文件输出流、文件输入/输出流,所以相应的必须将文件流说明为 ifstream、ofstream 和 fstream 类的对象,然后利用文件流的对象对文件进行操作。对文件的操作过程可按照一下四步进行:即定义文件流类的对象、打开文件、对文件进行读写操作、关闭文件。
2.2 文件的打开和关闭 2.2.1 定义流对象//流类 流对象; ifstream ifile; //定义一个文件输入流对象 ofstream ofile; //定义一个文件输出流对象 fstream iofile; //定义一个文件输出/输入流对象2.2.2 打开文件
定义了文件流对象后,就可以利用其成员函数 open()打开需要操作的文件,该成员函数的函数原为:
void open(const unsigned char *filename,int mode,int access=filebuf:openprot);
其中:filename 是一个字符型指针,指定了要打开的文件名;mode 指定了文件的打开方式,其值如下表所示;access 指定了文件的系统属性,取默认即可:
说明:
- 在实际使用过程中,可以根据需要将以上打开文件的方式用“|”组合起来。如:
ios::in|ios::out 表示以读/写方式打开文件 ios::in|ios:: binary 表示以二进制读方式打开文件 ios::out|ios:: binary 表示以二进制写方式打开文件 ios::in|ios::out|ios::binary 表示以二进制读/写方式打开文件
- 如果未指明以二进制方式打开文件,则默认是以文本方式打开文件。
对于 ifstream 流, mode 参数的默认值为 ios::in, 对于 ofstream 流,mode 的默 认值为 ios::out|ios::trunc, 对于 fstream 流, mode 的默认值为 ios::int|ios::out|ios::app
- 也可以通过,构造函数打开文件。
- 出错处理是通过,对类对象进行判断的。若文件打开成功,返回 1,否则返回
#include#include using namespace std; int main() { ifstream ifs("xxx.txt",ios::in); if(!ifs) cout<<"open error1"< >buf) cout< >buf; if(fs) cout< 2.2.3 文件的关闭 在文件操作结束(即读、写完毕)时应及时调用成员函数 close()来关闭文件。该函数比较简单,没有参数和返回值。
2.4 流文件状态与判断系统为了标识当前文件操作的状态,提供了标识位和检查标识位的函数。
2.4.1 标识位/// Indicates a loss of integrity in an input or output sequence (such /// as an irrecoverable read error from a file). static const iostate badbit =_S_badbit; /// Indicates that an input operation reached the end of an input sequence. static const iostate eofbit =_S_eofbit; /// Indicates that an input operation failed to read the expected /// characters, or that an output operation failed to generate the /// desired characters. static const iostate failbit =_S_failbit; /// Indicates all is well. static const iostate goodbit =_S_goodbit2.4.2 函数eof() 如果读文件到达文件末尾,返回 true。bad() 如果在读写过程中出错,返回 true 。例如:当我们要对一个不是打开为写状态的文件进行写入时, 或者我们要写入的设备没有剩余空间的时候。fail() 除了与 bad() 同样的情况下会返回 true 以外,加上格式错误时也返回 true ,例如 当想要读入一个整数,而获得了一个字母的时候。或是遇到 eof。good() 这是最通用的:如果调用以上任何一个函数返回 true 的话,此函数返回 false 。clear() 标识位一旦被置位,这些标志将不会被改变,要想重置以上成员函数所检查的状态标志, 你可以使用成员函数 clear(),没有参数。比如:通过函数移动文件指针,并不会使 eofbit自动重置#includeusing namespace std; int main() { int integerVal; cout << "Before a bad input operation:" << "n cin.eof(): " < >integerVal; // control + D/Z cout << "After a bad input operation:" << "n cin.eof(): " < 2.5 文件的读写操作
在打开文件后就可以对文件进行读写操作了。从一个文件中读出数据,可以使用文件流类的 get、getline、read 成员函数以及运算符“>>”;
而向一个文件写入数据,可以使用其 put、write 函数以及插入符“<<”;
2.5.1 读写文本文件读出
operator>> int get(); istream& get(int); istream & get(char*,int n, char deli ) istream& getline(char * ,int n)写入
operator<< osream put(int)#include#include using namespace std; int main() { fstream ifs("src.txt",ios::in); if(!ifs) { cout<<"open error"< 2.5.2 读写二进制文件 ostream & write(const char * buffer,int len); istream & read(char * buff, int len);#include#include using namespace std; struct Student { char name[100]; int num; int age; char sex; }; int main() { Student s[3] = { {"li",1001,18,'f'}, {"Fun",1002,19,'m'}, {"Wang",1004,17,'f'} }; ofstream ofs("student.data",ios::out|ios::trunc|ios::binary); if(!ofs){ cout<<"open error"< 3. (cin)和(!cin)的原理 在判断文件打开成功与否或是连续从流中读取数据时,就要用到对流对像的操作,比如if(!cin) 或是 whie(cin) 等等。
代码 while(cin>>val),我们都知道 cin 是一个流对象,而>>运算符返回左边的流对象,也就是说 cin>>val 返回 cin,于是 while(cin>>val)就变成了 while(cin),问题就变成了一个
流对象在判断语句中的合法性。不管是 while(cin)还是 if(cin),都是合法的,为什么呢?我们自己定义一个类,然后定义该类的对象,然后使用 if 语句来判断它是不合法的。这说明,流对象具有某种转换函数,可
以将一个流对象转换成判断语句可以识别的类型。打开 iostream.h 文件,找到 cin 的定义,发现是来自于istream.h,其中的模板类basic_istream 继承自 basic_ios,打开 basic_ios 的定义,发现它有两个重载函数。operator void *() const 和 bool operator!() const。这两个函数使得流对象可作为判断语句的内容。operator void*() const //转化函数 { return this->fail() ? 0 : const_cast(this); } bool operator!() const { return this->fail(); } 因此,可以简单的理解调用过程为:
while(cin) =====> while(!cin.fail()) //while the stream is OK while(!cin) =====> while(cin.fail()) //while the stream is NOT OK



