文章目录

MFC - CArchive/内存之间的序列化应用细节概述笔记END

MFC - CArchive/内存之间的序列化应用细节

概述

有个参数文件, 开始直接序列化到文件. 现在优化程序, 不想这个参数文件被用户看到. 想先由参数发布程序(自己用)设置好参数后, 加个密落地. 等用户拿到后, 由程序导入到程序运行时指定的数据目录. 程序运行时, 先解密参数文件到内存, 然后再由MFC序列化到类中的变量. 查了一下, 有大神出了文章(https://www.codeproject.com/Articles/1176939/All-About-MFC-Serialization), 将MFC序列化的各种细节都讲了.

不过有些细节要自己实验才能确定. e.g. CArchive向流中序列化写入不同的内容, 这个流空间需要开多长? 针对流的序列化, 自己做了实验, 用到的实现细节都测试了. 可以在自己工程中应用(CArchive/流之间的序列化)了.

笔记

void buf_save_to_ar(uint8_t* pBuf, UINT lenBuf)

{

bool b_rc = false;

CMemFile memFile;

uint64_t lenFile = 0;

do {

if ((NULL == pBuf) || (0 == lenBuf))

{

break;

}

// memFile.Close(); // @todo for test, 没有attch的时候, 也不会报错.

// lenFile = memFile.GetLength(); // 0 , 没有attach的时候, 或者关闭后, 不报错, 返回的文件长度为0

memFile.Attach(pBuf, lenBuf);

// lenFile = memFile.GetLength(); // 0x100, Attach Buffer后, 文件长度就是Buffer的长度

CArchive ar(&memFile, CArchive::store);

//ar << CString(_T("1")); // 如果buffer长度不足, 也不报错, 看来要将buffer长度给够

ff fe ff 01 31 00

//ar.Flush(); // for test

//ar << CString(_T("12")); // 如果buffer长度不足, 也不报错, 看来要将buffer长度给够

ff fe ff 02 31 00 32 00

//ar.Flush(); // for test

//ar << CString(_T("1"));

//ar.Flush(); // ff fe ff 01 31 00

//ar << CString(_T("2"));

ff fe ff 01 31 00 ff fe ff 01 32 00

//ar.Flush(); // for test

ar << CString(_T("hello")); // 如果buffer长度不足, 也不报错, 看来要将buffer长度给够

// ff fe ff 05 68 00 65 00 6c 00 6c 00 6f 00

ar.Flush(); // for test

// lenFile = ar.GetFile()->GetLength(); // 这个长度和序列化无关, 就是attach的buffer长度

ar << CString(_T("world"));

ar.Flush(); // for test

try {

// 如果buffer给的长度不够, 关闭ar时会报错

// catch不住

// 所以buffer要留够, 给序列化内容长度估算的1.1倍数, 可能靠谱一些

ar.Close();

// ff fe ff 05 68 00 65 00 6c 00 6c 00 6f 00 ff fe ff 05 77 00 6f 00 72 00 6c 00 64 00 ed ed fd fd fd fd

// 可以看到留出的保险字符位置并没有被覆盖

}

catch (CArchiveException* e)

{

e->IsSerializable();

b_rc = false;

break;

}

b_rc = true;

} while (false);

_ASSERT(b_rc);

memFile.Close();

}

void ar_load_from_ar(uint8_t* pBuf, UINT lenBuf)

{

bool b_rc = false;

CMemFile memFile;

CString csHello;

CString csWorld;

do {

if ((NULL == pBuf) || (0 == lenBuf))

{

break;

}

memFile.Attach(pBuf, lenBuf);

CArchive ar(&memFile, CArchive::load);

ar >> csHello;

// now csHello is _T("hello")

ar >> csWorld;

// now csWorld is _T("world")

ar.Close();

b_rc = true;

} while (false);

_ASSERT(b_rc);

memFile.Close();

}

void CTestArBufDlg::OnBnClickedButton1()

{

uint8_t* pBuf = NULL;

UINT lenBuf = 0; // 根据要写入的内容多少, 估算好长度后, 来开buffer

CString csTmp;

int iLenTmp = 0;

int i = 0;

int iCntCString = 0;

// 假设要序列化的是下面这2个CString

// CString(_T("hello"))

// CString(_T("world"))

csTmp = _T("hello");

iCntCString++;

iLenTmp = csTmp.GetLength(); // 5

lenBuf += iLenTmp;

csTmp = _T("world");

iCntCString++;

iLenTmp = csTmp.GetLength(); // 5

lenBuf += iLenTmp;

// ff fe ff 01 31 00

// 每次ar一次CString, 就需要增加4个字节(0xff, 0xfe, 0xff 可能是CString的类标记(以后遇到机会, 可以再试试别的数据类型), 01 代表CString的TCHAR字符数量)

// lenBuf 现在是WCHAR的数量, 要转成uint8_t的数量

lenBuf = lenBuf * sizeof(TCHAR);

lenBuf += (iCntCString * 4); // 存一次CString, 就有4个字节的头信息

lenBuf += sizeof(TCHAR); // 留个保险字节的位置

// now lenBuf is 0x16

// 开buffer

pBuf = new uint8_t[lenBuf];

_ASSERT(NULL != pBuf);

// 自己的内存调试标记可以为0xED. MFC调试标记为0xCD, 0xFD, 0xDD

memset(pBuf, 0xED, lenBuf);

// test use CArchive load-from/save-to buffer

// 如果向流中进行序列化写入, 则需要考虑开多大的流空间, 否则报错(catch不住)

buf_save_to_ar(pBuf, lenBuf);

// 如果是从流中载入序列化, 则不需要考虑buffer的长度, 因为这个buffer是已经确定的, 正确的(由前面的序列化写入保证)

ar_load_from_ar(pBuf, lenBuf);

// all ok

}

END

参考文章

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。