目录
CFile:文件操作类,封装了关于文件读写等操作,常见的方法:
代码如下:
#include <afxwin.h>
#include <iostream>
using namespace std;
void File( ){
CFile file;
// 没有文件就创建,然后可读可写
file.Open( "E:/MFC/Day07/file.txt", CFile::modeCreate|CFile::modeReadWrite );
char str[] = "hello file";
file.Write( str, strlen(str) );
file.SeekToBegin( );// 设置文件读写位置
char buf[256] = { 0 };
long nLen = file.Read( buf, 255 ); // 返回值是实际读到的数据
cout << buf << ' ' << nLen << endl;
file.Close();
}
int main(){
File();
return 0;
}
序列化作用:以二进制流形式读写硬盘文件,效率很高。
先把数据放到缓冲区,再放到硬盘上
序列化:往硬盘上写数据;
反序列化:从硬盘上读取数据。
代码如下:
#include <afxwin.h>
#include <iostream>
using namespace std;
void Store( ){//序列化(存储、写)数据
CFile file;
file.Open( "E:/MFC/Day07/serial.txt", CFile::modeCreate | CFile::modeWrite );
CArchive ar(&file, CArchive::store, 4096);//归档类对象,维护缓冲区。
long age = 18;
ar << age;//将18保存当前指向的位置,并向后移动当前指向,相应字节数。
float score = 88.5;
ar << score;//将88.5保存当前指向的位置,并向后移动当前指向,相应字节数。
CString name = "zhangsan";
ar << name;
ar.Close( );
file.Close( );
}
void Load( ){//反序列化(加载/读)
CFile file;
file.Open( "E:/MFC/day07/serial.txt", CFile::modeRead );
CArchive ar( &file, CArchive::load, 4096 );//维护一个buff,大小4096字节
long age;
ar >> age;//当反序列化第一个数据时候,内部将文件中所有数据读入ar维护的buff中
float score;
ar >> score;//当反序列化后续数据时候,不需要到硬盘文件中读取,直接到ar维护的buff中读取
CString name;
ar >> name;//当反序列化后续数据时候,不需要到硬盘文件中读取,直接到ar维护的buff中读取
ar.Close( );
file.Close( );
cout << age << ' ' << score << ' ' << name << endl;
}
int main(){
Store( );
Load( );
return 0;
}
问题:数据一共16字节,为啥是17个字节
原因:首先排除\0,如果在内存中会有这个符号,但是再硬盘不会有。多出的一个字节是描述字符串大小的。前四个字节是Int,后四个字节是float,中间一个字节是字符串长度为8
Windows记事本解析文件是按照字符解析,所以前面的数字乱码了。
数据结构:
class CArchive
{
enum Mode; // {store = 0,load = 1……}
BOOL m_nMode; // 访问方式
int m_nBufSize; // buff的大小
CFile* m_pFile; // 操作的文件对象
BYTE* m_lpBufCur; // 当前指向
BYTE* m_lpBufMax; // 终止指向
BYTE* m_lpBufStart; // 开始指向
}
CArchive ar(&file, CArchive::store, 4096);? 构造函数伪代码如下:
CFile file;
file.Open( "E:/MFC/Day07/serial.txt", CFile::modeCreate | CFile::modeWrite );
CArchive ar(&file, CArchive::store, 4096) === CArchive::CArchive(&file,0, 4096)
{
m_nMode = CArchive::store; // 0
m_pFile = &file;//“E:/....serial.txt”
m_nBufSize = 4096;
m_lpBufStart = new BYTE[m_nBufSize]; // 开辟一块堆内存,指向首地址
m_lpBufMax = m_lpBufStart + 4096;
m_lpBufCur = m_lpBufStart;
}
初始时
如何把数据存入缓冲区,伪代码如下:
long age = 18;
ar << age === CArchive::operator<<(age)//函数内部this为&ar
{
if (m_lpBufCur + sizeof(LONG) > m_lpBufMax)
{
Flush();
}
*m_lpBufCur = age;
m_lpBufCur += sizeof(LONG);
} // 把18存入缓冲区,并且指针后移4个字节
float score = 88.5;
ar << score === CArchive::operator<<(score)//函数内部this为&ar
{
if (m_lpBufCur + sizeof(float) > m_lpBufMax)
{
Flush();
}
*m_lpBufCur = score;//88.5
m_lpBufCur += sizeof(float);
}
CString name = "zhangsan";
ar << name === CArchive::operator<<(name)//函数内部this为&ar
{
AfxWriteStringLength(ar, 8 )
{
ar<<(unsigned char)nLength;//8
}
Write(name, 8)//函数内部this为&ar
{
memcpy_s(m_lpBufCur, (size_t)(m_lpBufMax - m_lpBufCur), name, 8);
m_lpBufCur += 8;
}
}
序列化三个数据后的缓冲区:
关闭文档类对象,释放缓冲区伪代码:把当前数据导入硬盘上,再重置当前指向
ar.Close( )//函数内部this为&ar
{
Flush()//函数内部this为&ar
{
&file->Write(m_lpBufStart, ULONG(m_lpBufCur - m_lpBufStart)); // 往硬盘写数据
m_lpBufCur = m_lpBufStart;//重置当前指向
}
}
如何需要写入4个字节,但是只剩3个字节的空间,怎么办?
会调用flush(),把缓冲区的数据写入到硬盘空间,再重置当前指针指向。再重新写入数据,相当于从头覆盖写入。
序列化执行过程总结:
反序列化执行过程总结: