【c++】文件操作
1. c++中的文件
2. 文件的打开和关闭
3. 文本文件的读写
4. 二进制文件的读写
5. 文件的定位
6. 文件的随机访问
参考:
《c++从入门到精通》 人民邮电出版社
1.C++中的文件
在c++中,文件按存储格式分为两种类型:
文本文件(又称ASCII码文件或字符文件)
二进制文件(又称字节文件)
在字符文件中,每个字节单元的内容为字符的ASCII码。
在字节文件中,文件内容是数据的内部表示,是从内存中直接复制过来的。
(1)对于字符信息,数据的内部表示就是ASCII码表示,所以在文本文件和二进制文件中保存的字符信息没有差别。
(2)但对于数值信息,数据的内部表示和ASCII码表示截然不同。
什么是文件?
文件是相关数据的集合。计算机中的程序、数据、文档通常都组织成文件存储在外存储器中。
由于输入输出设备具有字节流特征,所以操作系统也把他们看作是文件。例如:键盘是输入文件,显示器、打印机是输出文件。对于输入文件,只能从文件中读取数据(例如键盘);对于输出文件,智能向文件写入(例如打印机文件)。
C++如何使用文件?
要在程序中使用文件,需要包含“#include<fstream>”命令。由它提供文件流类:
ifstream(输入文件流类)
ofstream(输出文件流类)
fstream(输入输出文件流类)
文件在c++ 看来是字符流或二进制流,统称为文件流。要使用一个文件流,应遵循以下步骤:
(1) 先打开一个文件,目的是将一个文件流对象与某个磁盘文件联系起来。
(2) 然后,使用文件流对象的成员函数,将数据写入或读出。
(3) 关闭文件,即将文件流对象与磁盘文件脱离关系。
2.文件的打开和关闭
打开文件的方式有两种:
(1)用文件流的成员函数::open()打开文件
(2)用文件流类的构造函数打开文件
(1)用文件流的成员函数::open()打开文件
参数说明:
第一个参数:是要打开的文件名(可含路径)
第二个参数:指定文件的打开方式
第三个参数:指定打开文件时的保护方式,该参数与操作系统有关,通常使用默认值filebuf::openprot。
下表是对文件打开方式的说明。
(2) 用文件流类的构造函数打开文件
ifstream、ofstream 、fstream 3个文件流类的构造函数所带有的参数与 各自的成员函数open()的参数完全相同,具体方式如下:
(3) 判断打开文件是否成功
为了避免文件打开失败产生的异常错误,通常使用异常处理以提高程序的可靠性。判断文件打开与否的语句是:
//成员函数open() ifstream f1; f1.open("text.txt",ios::in); if(! f1) { cout<<"不能打开文件"<<endl; exit(1); }
或者:
//构造函数ifstream ifstream f1("text.txt",ios::in); if(! f1) { cout<<"不能打开文件"<<endl; exit(1); }
关闭文件
文件读写完毕,通常要关闭文件,目的是把暂存在内存缓冲区中的内容写入到文件中,并归还打开文件时申请的内存资源。这有利于系统回收相应的资源。
利用每个文件流类中的成员函数close()即可以实现关闭文件操作。
3.文本文件的读写
对文件流对象的基本操作和标准输入输出流的操作相同,即可通过提取运算符“>>”和插入运算符“<<”来读写文件。
程序实例:复制文本文件内容从f1->f2
//文件打开.cpp #include<iostream> #include<stdio.h> #include<fstream> #include<stdlib.h> // exit using namespace std; int main() { ifstream f1("in.txt",ios::in ); ofstream f2("out.txt",ios::out ); if(! f1) { cout<<"不能打开文件:in.txt"<<endl; exit(1); } if(! f2) { cout<<"不能打开文件:out.txt"<<endl; exit(1); } //复制操作 char ch; while(f1>>ch) //从f1中读取 { cout<<ch; f2<<ch; //向f2输出(即写入) } f1.close(); f2.close(); return 0; }
实验结果:
In.txt
Out.txt
4.二进制文件的读写
对二进制文件的读写要使用到文件流的成员函数read()和write()。读写时,数据不做任何变换,直接传送。
读操作
二进制文件的读,使用到文件流的成员函数read()。
这三个成员函数的功能相同,都是从二进制文件中读取n个字节数据到t指针所指的缓冲区。
注意:指针类型为字符型char*/unsigned/signed char*。其他类型的指针要做强制类型转换。
写操作
二进制文件的写,使用到文件流的成员函数write()。
这三个成员函数的功能相同,都是t指针所指的缓冲区 写入n个字节数据 到二进制文件中。
实例:向文件中写入1-100内的偶数。
方法一:按int型字节输入
for(int i=2;i<100;i=i+2) { f1.write((char *) &i,sizeof( int )); //将整型指针转化为字符型指针 }
会发现每一个数据是占四个字节(int型),(其余三个0代表NULL空字符,用来补位)。
方法二:按char型字节数写入
for(int i=2;i<100;i=i+2) { f1.write((char *) &i,sizeof(char)); //将整型指针转化为字符型指针 }
会发现每一个数据是占1个字节(char型)。
完整实例代码如下:
//二进制文件读取.cpp #include<iostream> #include<stdio.h> #include<fstream> #include<stdlib.h> // exit using namespace std; int main() { ofstream f1("out.dat",ios::out | ios::binary); //创建文件 if(! f1) { cout<<"不能打开文件:out.dat"<<endl; exit(1); } for(int i=2;i<100;i=i+2) { f1.write((char *) &i,sizeof(int)); //将整型指针转化为字符型指针 } f1.close(); cout<<"二进制文件写入完毕!"<<endl; ifstream f2; f2.open("out.dat",ios::in |ios::binary); //二进制文件的读写要表明文件类型 if(! f2) { cout<<"不能打开文件:out.dat"<<endl; exit(1); } char ch; f2.unsetf(ios::skipws); //跳过空格 while(f2>>ch) { if((ch)==NULL) ; //过滤空字符 else cout<<(int)ch<<" "; //只显示非空字符 } return 0; }
运行结果:
5.文件的定位
C++把每一个文件都看成一个有序的流,如图所示,每一个文件或以EOF(文件结束符)结束,或者在特定的字节号处结束。
当打开一个文件时,该文件就和某个文件流关联起来了。对文件进行读写实际上受到文件定位指针的控制:
输入流的指针也称为读指针。每一次提取操作>>将从读指针当前位置开始,然后每一次提取操作自动将读指针向文件尾部移动。
输出流的指针也称为写指针。每一次插入操作<<将从写指针当前位置开始,然后每一次插入操作,自动将写指针向文件尾部移动。
除了顺序读写,文件流类还支持文件的随机读写,即从文件的任何位置读或写数据。在C++中,可以由程序移动文件指针,从而实现文件的随机访问,即可读写文件流中的任意一段内容。
一般文本文件很难准确定位,所以随机访问多用于二进制文件。
使用举例如下:
6.二进制文件随机读取
文件随机访问分两步:
1. 先将文件读写位置移动到指定位置
2. 再用文件读写函数读取或写入数据
例如:将文件指针从当前位置 后移20*4个字节,再进行读取。
核心代码:
f2.seekg(20*sizeof(int) ,ios::cur); //将文件指针从当前位置 后移20*4个字节 for(int i=0;i<100&& !f2.eof(); i++) { f2.read((char *) &ch,sizeof(int )); //读取方式和写入方式相匹配 cout<<ch<<" "; }
完整代码:
//二进制文件随机读取.cpp #include<iostream> #include<stdio.h> #include<fstream> #include<stdlib.h> // exit using namespace std; int main() { ofstream f1("out.dat",ios::out | ios::binary); //创建文件 if(! f1) { cout<<"不能打开文件:out.dat"<<endl; exit(1); } for(int i=2;i<100;i=i+2) { f1.write((char *) &i,sizeof(int)); //将整型指针转化为字符型指针 } f1.close(); cout<<"二进制文件写入完毕!"<<endl; ifstream f2; f2.open("out.dat",ios::in |ios::binary); if(! f2) { cout<<"不能打开文件:out.dat"<<endl; exit(1); } int ch; f2.seekg(20*sizeof(int) ,ios::cur); //将文件指针从当前位置 后移10*4个字节 for(int i=0;i<100&& !f2.eof(); i++) { f2.read((char *) &ch,sizeof(int )); //读取方式和写入方式相匹配 cout<<ch<<" "; } f2.close(); return 0; }
运行结果:
从结果可发现,确实是从开头位置后移了20*4个字节,即10个int型数字后,开始读取的。
------------------------------------------- END -------------------------------------