
class CStudent
{
char szName[20]; //假设学生姓名不超过19个字符,以 '\0' 结尾
char szId[l0]; //假设学号为9位,以 '\0' 结尾
int age; //年龄
};
如果用文本文件存储学生的信息,文件可能是如下样子:ostream & write(char* buffer, int count);
该成员函数将内存中 buffer 所指向的 count 个字节的内容写入文件,返回值是对函数所作用的对象的引用,如 obj.write(...) 的返回值就是对 obj 的引用。#include
#include
using namespace std;
class CStudent
{
public:
char szName[20];
int age;
};
int main()
{
CStudent s;
ofstream outFile("students.dat", ios::out | ios::binary);
while (cin >> s.szName >> s.age)
outFile.write((char*)&s, sizeof(s));
outFile.close();
return 0;
}
输入:Tom烫烫烫烫烫烫烫烫 Jack烫烫烫烫烫烫烫? Jane烫烫烫烫烫烫烫?
istream & read(char* buffer, int count);
该成员函数从文件中读取 count 个字节的内容,存放到 buffer 所指向的内存缓冲区中,返回值是对函数所作用的对象的引用。int gcount();
read 成员函数从文件读指针指向的位置开始读取若干字节。文件读指针是 ifstream 或 fstream 对象内部维护的一个变量。文件刚打开时,文件读指针指向文件的开头(如果以ios::app 方式打开,则指向文件末尾),用 read 函数读取 n 个字节,读指针指向的位置就向后移动 n 个字节。因此,打开一个文件后连续调用 read 函数,就能将整个文件的内容读取出来。#include
#include
using namespace std;
class CStudent
{
public:
char szName[20];
int age;
};
int main()
{
CStudent s;
ifstream inFile("students.dat",ios::in|ios::binary); //二进制读方式打开
if(!inFile) {
cout << "error" < return 0; } while(inFile.read((char *)&s, sizeof(s))) { //一直读到文件结束 int readedBytes = inFile.gcount(); //看刚才读了多少字节 cout << s.szName << " " << s.age << endl; } inFile.close(); return 0; } mycopy 源文件名 目标文件名 mycopy src.dat dest.dat #include #include using namespace std; int main(int argc, char* argv[]) { if (argc != 3) { cout << "File name missing!" << endl; return 0; } ifstream inFile(argv[l], ios::binary | ios::in); //以二进制读模式打开文件 if (!inFile) { cout << "Source file open error." << endl; return 0; } ofstream outFile(argv[2], ios::binary | ios::out); //以二进制写模式打开文件 if (!outFile) { cout << "New file open error." << endl; inFile.close(); //打开的文件一定要关闭 return 0; } char c; while (inFile.get(c)) //每次读取一个字符 outFile.put(c); //每次写入一个字符 outFile.close(); inFile.close(); return 0; } 1. 二进制文件写入示例: //采用C模式写二进制文件void DataWrite_CMode(){//准备数据double pos[200];for(int i = 0; i < 200; i ++ )pos[i] = i ;//写出数据FILE *fid;fid = fopen("binary.dat","wb");if(fid == NULL){printf("写出文件出错");return;}int mode = 1;printf("mode为1,逐个写入;mode为2,逐行写入\n");scanf("%d",&mode);if(1==mode){for(int i = 0; i < 200; i++)fwrite(&pos[i],sizeof(double),1,fid);}else if(2 == mode){fwrite(pos, sizeof(double), 200, fid);}fclose(fid);}2. 二进制文件读取示例: //采用C模式读二进制文件void DataRead_CMode(){FILE *fid;fid = fopen("binary.dat","rb");if(fid == NULL){printf("读取文件出错");return;}int mode = 1;printf("mode为1,知道pos有多少个;mode为2,不知道pos有多少个\n");scanf("%d",&mode);if(1 == mode){double pos[200];fread(pos,sizeof(double),200,fid);for(int i = 0; i < 200; i++)printf("%lf\n", pos[i]);free(pos);}else if(2 == mode){//获取文件大小fseek (fid , 0 , SEEK_END); long lSize = ftell (fid); rewind (fid); //开辟存储空间int num = lSize/sizeof(double);double *pos = (double*) malloc (sizeof(double)*num); if (pos == NULL) { printf("开辟空间出错"); return; } fread(pos,sizeof(double),num,fid);for(int i = 0; i < num; i++)printf("%lf\n", pos[i]);free(pos); //释放内存}fclose(fid);}
Tom 60
Jack 80
Jane 40
第 18 行,判断文件是否已经读完的方法和 while(cin>>n) 类似,归根到底都是因为 istream 类重载了 bool 强制类型转换运算符。
第 19 行只是演示 gcount 函数的用法,删除该行对程序运行结果没有影响。
思考题:关于 students.dat 的两个程序中,如果 CStudent 类的 szName 的定义不是“char szName[20] ”而是“string szName”,是否可以?为什么?
用文件流类的 put 和 get 成员函数读写文件
可以用 ifstream 和 fstream 类的 get 成员函数(继承自 istream 类)从文件中一次读取一个字节,也可以用 ofstream 和 fstream 类的 put 成员函数(继承自 ostream 类) 向文件中一次写入一个字节。
例题:编写一个 mycopy 程序,实现文件复制的功能。用法是在“命令提示符”窗口输入:
解题的基本思路是每次从源文件读取一个字节,然后写入目标文件。程序如下:
操作系统在接收到写文件的请求时,也是先把要写入的数据在一个内存缓冲区中保存起来,等缓冲区满后,再将缓冲区的内容全部写入磁盘。关闭文件的操作就能确保内存缓冲区中的数据被写入磁盘。
尽管如此,要连续读写文件时,像 mycopy 程序那样一个字节一个字节地读写,还是不如一次读写一片内存区域快。每次读写的字节数最好是 512 的整数倍。