采用C语言序列化复杂结构体的方法。

来源:互联网 发布:flash编程入门教程 编辑:程序博客网 时间:2024/05/22 15:08

内容来自回答一个论坛上网友的提问。。 顺便写到博客里面。   问题为“ 求用纯C语言序列化复杂结构体的方法”

于是 给他写了这样一个链表的序列化代码

typedef struct _MyStruct
{
   
int
nA;
   
char
cB;
   
struct _MyStruct*
pNext;
}MYSTRUCT,
*
PMYSTRUCT;

一开始我的思路是 用 unsigned char uszBuf[8] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};这样一个很冷门的64位数值 作为分隔线,用来隔开每一个链表域。

所以衍生出这样的一段代码:

#include <stdlib.h>

#define OUT
#define IN

typedef
struct _MyStruct
{
   
int
nA;
   
char
cB;
   
struct _MyStruct*
pNext;
}MYSTRUCT,
*
PMYSTRUCT;

// 序列化写入文件,-1代表失败

int serialInToFile(IN PMYSTRUCT pList, IN const char* pFileName)
{
   
int nReturn = -1
;
    unsigned
char uszBuf[8] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
};

    FILE
* pFile = fopen(pFileName, "wb+"
);
   
if (!
pFile)
       
return
nReturn;

   
while (pList!=
NULL)
    {
        fwrite(pList,
1, 5, pFile);  // 5个字节 int + char

        pList = pList->pNext;
       
if
(pList)
            fwrite(uszBuf,
1, 8
, pFile);
    }

    fclose(pFile);

    nReturn
= 1
;
   
return
nReturn;
}

// 序列化写入文件,-1代表失败

int serialOutFromeFile(OUT PMYSTRUCT* ppList, IN const char* pFileName)
{
   
int nReturn = -1
;

    FILE
* pFile = fopen(pFileName, "rb"
);
    PMYSTRUCT pCurNode
= (PMYSTRUCT)malloc(sizeof
(MYSTRUCT));
    unsigned
char uszBuf[8] = {0
};
   
int i = 0
;
   
int* pA =
NULL;

   
if (!
pFile)
       
return
nReturn;

   
*ppList =
pCurNode;
   
while(!
feof(pFile))
    {
        pCurNode
->pNext =
NULL;
        fread(uszBuf,
1, 4
, pFile);
        pA
= (int*
)uszBuf;
        pCurNode
->nA = *
pA;
        fscanf(pFile,
"%c", &(pCurNode->
cB));
        fread(uszBuf,
1, 8
, pFile);
       
       
for (i = 0; i < 8; i ++
)
        {
           
if (uszBuf[i] != 0xff
)
               
break
;
        }
       
if (i == 8
)
        {
            pCurNode
->pNext = (PMYSTRUCT)malloc(sizeof
(MYSTRUCT));
            pCurNode
= pCurNode->
pNext;
        }
    }

    fclose(pFile);
    nReturn
= 1
;
   
return
nReturn;
}
void
InitStruct(PMYSTRUCT pSTest)
{
    pSTest
->nA = 1
;
    pSTest
->cB = 'C'
;
    pSTest
->pNext = (PMYSTRUCT)malloc(sizeof
(MYSTRUCT));
    pSTest
->pNext->nA = 2
;
    pSTest
->pNext->cB = 'A'
;
    pSTest
->pNext->pNext =
NULL;
}
void
DeleteStruct(PMYSTRUCT pSTest)
{
    PMYSTRUCT pTmp
=
NULL;
   
while (pSTest!=
NULL)
    {
        pTmp
=
pSTest;
        pSTest
= pSTest->
pNext;
        free(pTmp);
    }
}
void
printStruct(PMYSTRUCT pSTest)
{
   
int i = 0
;
   
while (pSTest!=
NULL)
    {
       
++
i;
        printf(
"第%d, nA = %d, cB = %c /n", i, pSTest->nA, pSTest->
cB);
        pSTest
= pSTest->
pNext;
    }
}
int main(int argc, _TCHAR*
argv[])
{
   
int nReturn = 0
;
   
const char* pFileName = "fileSerial.tmp"
;
    PMYSTRUCT pSTest
= (PMYSTRUCT)malloc(sizeof
(MYSTRUCT));

    InitStruct(pSTest);

   
// 序列化

    nReturn = serialInToFile(pSTest, pFileName);
   
// 删除

    DeleteStruct(pSTest);
   
if (nReturn == -1
)
       
return
nReturn;

    pSTest
=
NULL;
   
// 导出

    serialOutFromeFile(&pSTest, pFileName);
   
// 打印

    printStruct(pSTest);
   
// 删除

    DeleteStruct(pSTest);

   
return 0
;
}

 

但是这哥们似乎需要更复杂的树形结构体, 这就得思考一下了。

即有左子树,又有右子树, 内部还有链表变量, 所以上述分隔标志不足以区分链式结构属于哪个分支。。 需要多增加一个标志。

于是我设计了如下判断标志

// 下面字符代表有指针数据
static unsigned char uszBufPointer[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
// 下面字符代表有指针结束

static unsigned char uszBufEnd[8] = {0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};

 

并且尝试了这样一种复杂结构:

 typedef struct _XY
{
  
int
nX;
  
struct _XY*
pNext;
}XY,
*
PXY;
typedef
struct
_MyStruct
{
   
int
nA;
   
char
cB;
    PXY pXY;
   
struct _MyStruct*
pLNext;
   
struct _MyStruct*
pRNext;
}MYSTRUCT,
*
PMYSTRUCT;

这次采用随机数初始化, 然后序列化的代码如下:

// 序列化.cpp : 定义控制台应用程序的入口点。
//
#include <stdlib.h>
#include
<stdlib.h>
#include
<time.h>

#define random(x) (rand()%x)

#define OUT
#define IN

typedef
struct _XY
{
  
int nX;
  
struct _XY* pNext;
}XY,
* PXY;
typedef
struct _MyStruct
{
   
int nA;
   
char cB;
    PXY pXY;
   
struct _MyStruct* pLNext;
   
struct _MyStruct* pRNext;
}MYSTRUCT,
*PMYSTRUCT;

// 下面字符代表有指针数据
static unsigned char uszBufPointer[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
// 下面字符代表有指针结束
static unsigned char uszBufEnd[8] = {0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};

// 递归序列化
void serialIn(PMYSTRUCT pList, FILE* pFile)
{
   
if (pList == NULL)
    {
       
// 写入不存在后续指针标志
        fwrite(uszBufEnd, 1, 8, pFile);
       
return;
    }

   
// 写入存在后续指针标志
    fwrite(uszBufPointer, 1, 8, pFile);
   
// 写入常量
    fwrite(pList, 1, 5, pFile);  // 先写入5个字节 int + char

   
// 写入pXY结构体
    PXY pXY = pList->pXY;
   
while (pXY != NULL)
    {
       
// 写入存在后续指针标志
        fwrite(uszBufPointer, 1, 8, pFile);
       
// 写入数据
        fwrite(&(pXY->nX), 1, 4, pFile);

        pXY
= pXY->pNext;
    }
   
// 写入结束标志
    fwrite(uszBufEnd, 1, 8, pFile);

   
// 写入左子树
    serialIn(pList->pLNext, pFile);
   
// 写入结束标志
    fwrite(uszBufEnd, 1, 8, pFile);

   
// 写入右子树
    serialIn(pList->pRNext, pFile);
   
// 写入结束标志
    fwrite(uszBufEnd, 1, 8, pFile);
}
// 序列化写入文件,-1代表失败
int serialInToFile(IN PMYSTRUCT pList, IN const char* pFileName)
{
   
int nReturn = -1;
   
    FILE
* pFile = fopen(pFileName, "wb+");
   
if (!pFile)
       
return nReturn;

   
// 递归序列化
    serialIn(pList, pFile);

    fclose(pFile);
    nReturn
= 1;
   
return nReturn;
}

unsigned
char szBuf[8] = {0};
// 判断是否有下一个指针域
int judgeIfHaveNextPointer(unsigned char* pBuf)
{
   
int nReturn = 0;
   
int i = 0;
   
for (i = 0; i < 8; i ++)
       
if (pBuf[i] != 0x00)
           
break;
   
if (i != 8)       // 说明可能有指针域
    {
       
for (i = 0; i < 8; i ++)
           
if (pBuf[i] != 0xff)
               
break;
       
if (i == 8)   // 有指针域
        {
            nReturn
= 1;
           
return nReturn;
        }
    }
   
else
       
return nReturn;

   
return nReturn;
}
unsigned
char uszTmpBuf[5] = {0};
// 递归读入
void serialRead(OUT PMYSTRUCT* ppList, FILE* pFile)
{
   
// 首先读8个字节判断是否有下一个节点
    fread(szBuf, 1, 8, pFile);
   
int nTmp = judgeIfHaveNextPointer(szBuf);
   
if (nTmp == 0)
       
return;

   
// 声明指针域
    *ppList = new MYSTRUCT;
    (
*ppList)->pXY = NULL;
    (
*ppList)->pLNext = NULL;
    (
*ppList)->pRNext = NULL;

    
// 先读入5个字节, int + char
    fread(uszTmpBuf, 1, 5, pFile);
   
int* pInteger = (int*) uszTmpBuf;
    (
*ppList)->nA = *pInteger;
   
char* pChar = (char*) (uszTmpBuf + 4);
    (
*ppList)->cB = *pChar;

   
// 获取pXY区域
    fread(szBuf, 1, 8, pFile);
    nTmp
= judgeIfHaveNextPointer(szBuf);
   
if(nTmp == 1)
    {
        (
*ppList)->pXY = new XY;
        PXY pXY
= (*ppList)->pXY;
       
do
        {
            pXY
->pNext = NULL;

           
// 读取4个字节 int
            fread(uszTmpBuf, 1, 4, pFile);
            pInteger
= (int*) uszTmpBuf;
            pXY
->nX = *pInteger;

            fread(szBuf,
1, 8, pFile);
            nTmp
= judgeIfHaveNextPointer(szBuf);
           
if (nTmp == 1)
            {
                pXY
->pNext = new XY;
                pXY
= pXY->pNext;
            }
        }
while (nTmp == 1);
    }

   
// 左孩子指针
    serialRead(&((*ppList)->pLNext), pFile);
    fread(szBuf,
1, 8, pFile);
   
// 右孩子指针
    serialRead(&((*ppList)->pRNext), pFile);
    fread(szBuf,
1, 8, pFile);
}
// 序列化读入文件,-1代表失败
int serialOutFromeFile(OUT PMYSTRUCT* ppList, IN const char* pFileName)
{
   
int nReturn = -1;

    FILE
* pFile = fopen(pFileName, "rb");
    PMYSTRUCT pCurNode
= (PMYSTRUCT)malloc(sizeof(MYSTRUCT));
    unsigned
char uszBuf[8] = {0};
   
int i = 0;
   
int* pA = NULL;

   
if (!pFile)
       
return nReturn;

    serialRead(ppList, pFile);


    fclose(pFile);
    nReturn
= 1;
   
return nReturn;
}

// 初始化成为一个复杂的结构系统
void InitStruct(PMYSTRUCT pSTest, int nA)
{
    pSTest
->pXY = NULL;
    pSTest
->pLNext = NULL;
    pSTest
->pRNext = NULL;
   
if (nA == 0)
    {
        pSTest
->nA = 0;
        pSTest
->cB = 0;
       
return;
    }
   
// 撒下随机数种子,产生一个20以内的随机数
    srand((int)time(0));
   
int nRand = random(20);

   
// 赋值
    pSTest->nA = nRand;
   
if (nRand > 10)
        pSTest
->cB = 'A' + nRand;
   
else
        pSTest
->cB = 'a' + nRand;

   
// 自带的结构体
    pSTest->pXY = new XY;
    PXY pXY
= pSTest->pXY;
    pXY
->pNext = NULL;
   
for(int i = 0; i < nRand / 4; i ++)
    {
        pXY
->nX = nRand - i;
        pXY
->pNext = new XY;
        pXY
= pXY->pNext;
        pXY
->pNext = NULL;
    }
    pXY
->nX = nRand + 1;
    pXY
->pNext = NULL;

   
// 对于两个左右节点赋值
    pSTest->pLNext = new MYSTRUCT;
    InitStruct(pSTest
->pLNext, nA - 1);
    pSTest
->pRNext = new MYSTRUCT;
    InitStruct(pSTest
->pRNext, nA - 1);
}

// 递归删除
void DeleteStruct(PMYSTRUCT pSTest)
{
   
if(pSTest == NULL)
       
return;

    PXY pXY
= pSTest->pXY;
   
while (pXY != NULL)
    {
        PXY pTmp
= pXY;
        pXY
= pXY->pNext;
        delete pTmp;
    }
    pSTest
->pXY = NULL;

   
// 删除左右子树
    DeleteStruct(pSTest->pLNext);
    pSTest
->pLNext = NULL;
    DeleteStruct(pSTest
->pRNext);
    pSTest
->pRNext = NULL;

   
// 删除自己
    delete pSTest;
}

// 递归打印数据
void printStruct(PMYSTRUCT pSTest,int nNum)
{
   
if(pSTest == NULL)
    {
        printf(
"NULL");
       
return;
    }

    printf(
"/n 第%d层节点数据/n", nNum);
    printf(
"nA = %d, cB = %c  XY---> ", pSTest->nA, pSTest->cB);
   
int i = 0;
    PXY pXY
= pSTest->pXY;
   
while (pXY != NULL)
    {
       
++i;
        printf(
"第%d个XY,  nX = %d ---> ", i, pXY->nX);
        pXY
= pXY->pNext;
    }
    printf(
"NULL");

   
// 打印子节点
    printf("/n打印下一层左孩子节点");
    printStruct(pSTest
->pLNext, nNum + 1);
    printf(
"/n打印下一层右孩子节点");
    printStruct(pSTest
->pRNext, nNum + 1);
}
int main(int argc, _TCHAR* argv[])
{
   
int nReturn = 0;
   
const char* pFileName = "fileSerial.tmp";
   
const char* pFileName2 = "fileSerial2.tmp";
    PMYSTRUCT pSTest
= new MYSTRUCT;

   
// 初始化
    InitStruct(pSTest, 5);  // 2层比较好调试,5层
   
// 打印
    printStruct(pSTest, 0);
   
// 序列化
    serialInToFile(pSTest, pFileName);
   
// 删除
    DeleteStruct(pSTest);
    pSTest
= NULL;
   
   
// 导出序列化
    serialOutFromeFile(&pSTest, pFileName);
   
// 打印
    printf("/n/n---------------------------------/n");
    printStruct(pSTest,
0);
   
// 再次序列化,对比内容
    serialInToFile(pSTest, pFileName2);
   
// 删除
    DeleteStruct(pSTest);

    getchar();
   
return 0;
}
原帖地址http://topic.csdn.net/u/20110411/19/2d33c6ec-fe47-4ffd-8f27-44615a44af85.htmls

原创粉丝点击