自定义 序列化2

今天可以开始步入序列化的实质阶段了,定义CSerialization作为序列化的入口(持续更新中)

class EXPORTED_JHMF CSerialization
{
public:
 CSerialization();
 ~CSerialization();
 jbool  Serialize(CJObject* pObj,CJStream* pStream);  //开始序列化对象
 CJObject* DeSerialize(CJStream* pStream);
 jint32  EngenObjeID(){return ++m_ObjID;}
 jint32  EngenObjeTypeID(){return ++m_ObjTypeID;}
 jbool  CheckTypeCompatible(CJSerializationInfo* pinfs,CJSerializationInfo* sinfo);
 void  AddObjectSerializationInfos(CJSerializationInfo* pinfs);
 jint32  GetInstanceID(CJObject* pObj,jint32 parentID,jint32 findex,jbool bref);

 void     AddToFix(CHasReadedObject* pReadObj);
 CHasReadedObject*  AddReadedInstances(CJObject* pObj,jint32 typeID,jint32 id,jint32 parentid);
 CHasReadedObject*  GetHasReadedObject(jint32 id);
 CJSerializationInfo* GetObjectSerializationInfos(CJString name);
 CJSerializationInfo* GetObjectSerializationInfos(jint32 typeID);

 CJSerializationInfo* GetCurrentObjectSerializationInfos(jint32 typeID,CJObject* pObj);

public:
 CJStackT<CJObject*> m_objStack;
 static const jint32    topID = 1;
private:
 jint32    m_ObjID;
 jint32    m_ObjTypeID;
 CStringHashTable m_ObjectsInfos;
 CJListT<CJSerializationInfo*>  m_ObjectSerializationInfos;
 

 CJListT<CTOWriteObject*> m_ObjectInstancesCache;

 C2IntHashTable  m_WriteObjectInstances;
 C2IntHashTable  m_ReadedObjectInstances;
 C2IntHashTable  m_FixingObjects;   //等待修复的对象
 C2IntHashTable  m_CurrentObjectSerializationInfos;//当前对象类型信息(运行时动态库)
};

 

 

一步一步来, 先实现序列化的写部分,也就是序列化部分,让后再实现反序列化部分

首先要准备2个映射表,一是对象类型表,也就是保存在hash表m_ObjectsInfos中,另一个是对象实例映射表,保存在hash表m_ObjectsInfos中ObjectInstances

为了提高存储效率,定义了基础数据类型,这种数据类型一旦定义,被序列化后就不能版本兼容了,比如坐标类CJPoint 序列化后如果修改了该类,反序列化的时候就会错位,所以基础数据类型的使用需要特别小心。

对于基本数据类型,比如 int32 CJString 等作为原始数据处理

定义:

 

#define FIELDTYPE_OBJ    1
#define FIELDTYPE_OBJPTR   2
#define FIELDTYPE_PRIMITIVE   3

 

#define PRIMITIVETYPE_Invalid  1
#define PRIMITIVETYPE_Boolean  2
#define PRIMITIVETYPE_Byte   3
#define PRIMITIVETYPE_Char   4
#define PRIMITIVETYPE_Currency  5
#define PRIMITIVETYPE_Decimal  6
#define PRIMITIVETYPE_Double  7
#define PRIMITIVETYPE_Int16   8
#define PRIMITIVETYPE_Int32   9
#define PRIMITIVETYPE_Int64   10
#define PRIMITIVETYPE_SByte   11
#define PRIMITIVETYPE_Single  12
#define PRIMITIVETYPE_TimeSpan  13
#define PRIMITIVETYPE_DateTime  14
#define PRIMITIVETYPE_UInt16  15
#define PRIMITIVETYPE_UInt32  16
#define PRIMITIVETYPE_UInt64  17
#define PRIMITIVETYPE_Null   18
#define PRIMITIVETYPE_String  19

 

#define SER_HRADERTYPE_OBJINFO  1
#define SER_HRADERTYPE_OBJHEADER 2
#define SER_HRADERTYPE_ARRAY  3
#define SER_HRADERTYPE_BASEDATA  4


#define SER_HRADERTYPE_OBJMEMBER 0x10
#define SER_HRADERTYPE__Invalid  (PRIMITIVETYPE_Invalid + SER_HRADERTYPE_OBJMEMBER)
#define SER_HRADERTYPE_Boolean  (PRIMITIVETYPE_Boolean + SER_HRADERTYPE_OBJMEMBER)
#define SER_HRADERTYPE_Byte   (PRIMITIVETYPE_Byte + SER_HRADERTYPE_OBJMEMBER)
#define SER_HRADERTYPE_Char   (PRIMITIVETYPE_Char + SER_HRADERTYPE_OBJMEMBER)
#define SER_HRADERTYPE_Currency  (PRIMITIVETYPE_Currency + SER_HRADERTYPE_OBJMEMBER)
#define SER_HRADERTYPE_Decimal  (PRIMITIVETYPE_Decimal + SER_HRADERTYPE_OBJMEMBER)
#define SER_HRADERTYPE_Double  (PRIMITIVETYPE_Double + SER_HRADERTYPE_OBJMEMBER)
#define SER_HRADERTYPE_Int16  (PRIMITIVETYPE_Int16 + SER_HRADERTYPE_OBJMEMBER)
#define SER_HRADERTYPE_Int32  (PRIMITIVETYPE_Int32 + SER_HRADERTYPE_OBJMEMBER)
#define SER_HRADERTYPE_Int64  (PRIMITIVETYPE_Int64 + SER_HRADERTYPE_OBJMEMBER)
#define SER_HRADERTYPE_SByte  (PRIMITIVETYPE_SByte + SER_HRADERTYPE_OBJMEMBER)
#define SER_HRADERTYPE_Single  (PRIMITIVETYPE_Single + SER_HRADERTYPE_OBJMEMBER)
#define SER_HRADERTYPE_TimeSpan  (PRIMITIVETYPE_TimeSpan + SER_HRADERTYPE_OBJMEMBER)
#define SER_HRADERTYPE_DateTime  (PRIMITIVETYPE_DateTime + SER_HRADERTYPE_OBJMEMBER)
#define SER_HRADERTYPE_UInt16  (PRIMITIVETYPE_UInt16 + SER_HRADERTYPE_OBJMEMBER)
#define SER_HRADERTYPE_UInt32  (PRIMITIVETYPE_UInt32 + SER_HRADERTYPE_OBJMEMBER)
#define SER_HRADERTYPE_UInt64  (PRIMITIVETYPE_UInt64 + SER_HRADERTYPE_OBJMEMBER)
#define SER_HRADERTYPE_Null   (PRIMITIVETYPE_Null + SER_HRADERTYPE_OBJMEMBER)
#define SER_HRADERTYPE_String  (PRIMITIVETYPE_String + SER_HRADERTYPE_OBJMEMBER)


#define SER_HRADERTYPE_END   0xFF

 

好像有点说不清楚了,表达能力还真是不行啊,先不管那么多,定义一个对象写的类,专门写对象

class CObjectWrite
{
public:
 CObjectWrite(CSerialization* pSer,CJObject* pObj,jint32 id,CJStream* pStream);
 void Write();
 void WriteMember();
 void WriteObjectInfo(CSerialization::ObjectSerializationInfos* pObjSerinfos);
 void WriteObjectHeader();
 void WriteObjectEnd();
 void WritePrimitive(CJSerializationInfo::SerializationInfoField* pMember);
 void WriteBaseDataObject(CJObject* pObj);
private:
 CSerialization* m_pSerialization;
 CJObject*  m_pObj;
 CJStream*  m_pStream;
 CJSerializationInfo m_SerializationInfos;
 jint32   m_ObjID;
 CSerialization::ObjectSerializationInfos* m_ObjectInfos;

 CSerialization::ObjectSerializationInfos* GetObjectSerializationInfos(CJObject* pObj,CJSerializationInfo* pSeris);
};

 

开始实现序列化

jbool CSerialization::Serialize(CJObject* pObj,CJStream* pStream)
{
 if(pObj == JNULL)return FALSE;
 //首先,写序列化头
 pStream->WriteInt32(0xFF78FF78);
 pStream->WriteChar('J');
 pStream->WriteChar('H');
 pStream->WriteChar('M');
 pStream->WriteChar('F');
 //写序列化头
 //顶层对象ID

 m_objStack.Enqueue(pObj);

 CJObject* writeObj = JNULL;
 while((writeObj = m_objStack.Dequeue()) != JNULL)
 {
  //将对象写入
  if(writeObj->GetType() == JTYPEOF(CTOWriteObject))
  {
   CTOWriteObject* ptwObj = (CTOWriteObject*)writeObj;
   CObjectWrite objwrite(this,ptwObj->m_pObject,ptwObj->m_objID,pStream);
   objwrite.Write();
   //这时候不能直接删除CTOWriteObject对象,因为在哈希表中还需要继续使用它,所以只能把他放到最后删除
  }
  else
  {
   CObjectWrite objwrite(this,writeObj,-1,pStream);
   objwrite.Write();
  }
 }


 //结束序列化
 pStream->WriteByte(0xFF);
 pStream->WriteChar('E');
 pStream->WriteChar('N');
 pStream->WriteChar('D');
 return TRUE;
}

看这代码没什么意思,基本的意思很简单,从(栈)队列中取出一个一个对象,然后调用CObjectWrite 对象把对象写到流中去。简单吧

 

 

然后看CObjectWrite 对象的写函数

void CObjectWrite::Write()
{
 //首先获取序列化信息
 m_pObj->GetObjectData(&m_SerializationInfos);
 //获取对象类型信息
 m_ObjectInfos = GetObjectSerializationInfos(m_pObj,&m_SerializationInfos);

 //开始写对象实例
 WriteObjectHeader();
 if(m_pObj->GetType().IsArray())
 {
  //数组
  CJObjectArray* pArray = (CJObjectArray*)m_pObj;
  m_pStream->WriteByte(SER_HRADERTYPE_ARRAY);
  m_pStream->WriteInt32(pArray->GetLength());
  for(int i = 0;i < pArray->GetLength();i++)
  {
   CJObject* pObj = pArray->GetItem(i);
   jint32 id = m_pSerialization->GetInstanceID(pObj);
   m_pStream->WriteInt32(id);
  }
 }
 else if(m_pObj->GetType().IsSubclassOf(JTYPEOF(CJBaseDataType)))
 {
  //基础数据类型,直接写
  WriteBaseDataObject(m_pObj);
 }
 else
 {
  WriteMember();
 }
 WriteObjectEnd();
}

 

这个函数也简单,它只关心一个对象的写过程

首先是获取该对象的序列化信息,保存在SerializationInfos中,其次获取对象的类型信息,如果该类型信息不存在,就创建它,并把类型信息写到流里面去

GetObjectSerializationInfos的实现

CSerialization::ObjectSerializationInfos* CObjectWrite::GetObjectSerializationInfos(CJObject* pObj,CJSerializationInfo* pSeris)
{
 CJString classname = pObj->GetType().GetName();
 CSerialization::ObjectSerializationInfos* objInfos =m_pSerialization-> GetObjectSerializationInfos(classname);
 if(objInfos == JNULL)
 {
  objInfos = new CSerialization::ObjectSerializationInfos();
  objInfos->name = classname;
  objInfos->count = pSeris == JNULL?0:pSeris->GetStatisticsCount();
  objInfos->typeID = m_pSerialization->EngenObjeTypeID();
  if(objInfos->count > 0)
  {
   objInfos->infos = new CSerialization::ObjectSerializationInfo[objInfos->count];
   jint32 index = 0;
   CJSerializationInfo::SerializationInfoField* tmp = pSeris->m_fields.GetHead();
   while(tmp != JNULL)
   {
    objInfos->infos[index].Name = tmp->name;
    objInfos->infos[index].TypeID = tmp->fieldTypeID;
    objInfos->infos[index].Valuetypeid = tmp->valuetypeid;
    index++;
    tmp = pSeris->m_fields.GetNext(tmp);
   }
  }
  //写对象信息
  WriteObjectInfo(objInfos);
  m_pSerialization->AddObjectSerializationInfos(objInfos);
 }
 else if(!m_pSerialization->CheckTypeCompatible(objInfos,&m_SerializationInfos))
 {
  CJString msg;
  msg.Format("序列化类型不一致:%s",classname);
  JThrowSerialException((LPCTJSTR)msg);
 }
 return objInfos;

}

 

然后序列化内容,如果该对象是数组要另外处理,如是基础数据类型就直接写

最后开始写对象的成员类型WriteMember代码如下:

void CObjectWrite::WriteMember()
{
 CJSerializationInfo::SerializationInfoField* tmp = m_SerializationInfos.m_fields.GetHead();
 while(tmp != JNULL)
 {
  
  switch(tmp->fieldTypeID)
  {
  case FIELDTYPE_OBJ:
   if(tmp->value->GetType().IsSubclassOf(JTYPEOF(CJBaseDataType)))
   {
    //基础数据类型,直接写入
    WriteBaseDataObject(tmp->value);
    break;
   }
  case FIELDTYPE_OBJPTR:
   //获取该象的ID,如果该对象已经被加入到序列化队列就直接使用它的id,否则创建id并加入到序列化队列中去
   {
   jint32 id = m_pSerialization->GetInstanceID(tmp->value);
   m_pStream->WriteByte(SER_HRADERTYPE_OBJMEMBER);
   m_pStream->WriteInt32(id);
   }
   break;
  case FIELDTYPE_PRIMITIVE:
   WritePrimitive(tmp);
   break;
  default:
   {
    CJString msg;
    msg.Format("序列化对象成员类型无法识别:%s.%s",m_ObjectInfos->name,tmp->name);
    JThrowSerialException((LPCTJSTR)msg);
   }
   break;
  }


  tmp = m_SerializationInfos.m_fields.GetNext(tmp);
 }
}

如果成员是对象或者对象指针,就把它加入到对象(栈)队列中去,这里只记录它的ID即可

最后就是写原始类型数据了WritePrimitive

void CObjectWrite::WritePrimitive(CJSerializationInfo::SerializationInfoField* pMember)
{
 jbyte vtid = pMember->valuetypeid + SER_HRADERTYPE_OBJMEMBER;
 m_pStream->WriteByte(vtid);
 switch(vtid)
 {
 case SER_HRADERTYPE_Boolean:
  m_pStream->WriteInt32(*(jbool*)pMember->value);
  break;
 case SER_HRADERTYPE_Byte:
  m_pStream->WriteByte(*(jbyte*)pMember->value);
  break;
 case SER_HRADERTYPE_Char:
  m_pStream->WriteChar(*(char*)pMember->value);
  break;
 case SER_HRADERTYPE_Double:
  m_pStream->WriteDouble(*(double*)pMember->value);
  break;
 case SER_HRADERTYPE_Int16:
  m_pStream->WriteInt16(*(jint16*)pMember->value);
  break;
 case SER_HRADERTYPE_Int32:
  m_pStream->WriteInt32(*(jint32*)pMember->value);
  break;
 case SER_HRADERTYPE_Int64:
  m_pStream->WriteInt64(*(jint64*)pMember->value);
  break;
 case SER_HRADERTYPE_Single:
  m_pStream->WriteFloat(*(float*)pMember->value);
  break;
 case SER_HRADERTYPE_UInt16:
  m_pStream->WriteUInt16(*(juint16*)pMember->value);
  break;
 case SER_HRADERTYPE_UInt32:
  m_pStream->WriteUInt32(*(juint32*)pMember->value);
  break;
 case SER_HRADERTYPE_UInt64:
  m_pStream->WriteUInt64(*(juint64*)pMember->value);
  break;
 case SER_HRADERTYPE_String:
  m_pStream->WriteString(*(CJString*)pMember->value);
  break;
 case SER_HRADERTYPE_SByte:
 case SER_HRADERTYPE_Null:
 case SER_HRADERTYPE__Invalid:
 case SER_HRADERTYPE_TimeSpan:
 case SER_HRADERTYPE_DateTime:
 case SER_HRADERTYPE_Currency:
 case SER_HRADERTYPE_Decimal:
 default:
  {
   CJString msg;
   msg.Format("序列化对象成员基础数据类型无法识别:%s.%s",m_ObjectInfos->name,pMember->name);
   JThrowSerialException((LPCTJSTR)msg);
  }
  break;
 } 
}    

 

这样,整个序列化过程就算完成了,可能隐患不少,等反序列化过程完成就可以相互验证了。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值