采用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
- 采用C语言序列化复杂结构体的方法。
- C语言,结构体中字符串的声明(采用字符指针还是字符数组)
- 详解keil采用C语言模块化编程时全局变量、结构体的定义、声明以及头文件包含的处理方法!
- 详解keil采用C语言模块化编程时全局变量、结构体的定义、声明以及头文件包含的处理方法!
- [原]详解keil采用C语言模块化编程时全局变量、结构体的定义、声明以及头文件包含的处理方法!
- 移植C++语言到delphi时,复杂结构体的简单处理
- 黑马程序员——c语言复杂数据类型:结构体和枚举,typedef的使用
- 黑马程序员——c语言的复杂数据类型:指针和结构体
- C语言中复杂声明的解释方法
- C语言的复杂声明
- 复杂的C 语言声明
- C语言的复杂声明
- c语言中往缓存写入结构体的方法
- C语言中定义结构体的几种方法
- C语言结构体初始化的三种方法
- C语言结构体初始化的三种方法
- C 语言 结构体定义变量的三种方法
- C语言中定义结构体的几种方法
- 三星I5800上网设置
- codeforces #71 B. Colorful Field 二分
- Qt编码风格
- Windows Mobile使用.NET Compact Framework开发Winform时如何Dispose资源
- 5·1 劳动节该玩点啥?
- 采用C语言序列化复杂结构体的方法。
- 倍增排序
- java中final、finaliy、finalize的区别
- timsort
- samplesort
- 用二叉查找数排序
- ARM的ADS汇编器与GCC汇编器
- 详解Spring3基于Annotation的依赖注入实现
- DataGridView用法笔记