前言

  C中对体系化探讨少, 因为许多传输的剧情都有温馨分析的轮子.
对于类别化本质是统一编码, 统一解码的方式.

本文研商是一种简易的系列化方案. 保障差异应用端都能分析出正确结果.

在小说一初步, 看3个最不难易行的连串化代码 如下

#include <stdio.h>
#include <stdlib.h>

#define _INT_NAME        (64)
#define _STR_TXT        "student.struct"

struct student {
    int id;
    char sex;
    int age;
    char name[_INT_NAME + 1];
    double high;
    double weight;
};

// struct student 结构体序列化到文件的方法
static void _student_serialize(struct student* stu, FILE* txt) {
    fprintf(txt, "%d %c %d %s %lf %lf ", stu->id, stu->sex, 
        stu->age, stu->name, stu->high, stu->weight);
}

// struct student 结构体反序列化
static void _student_deserialize(struct student* stu, FILE* txt) {
    fscanf(txt, "%d %c %d %s %lf %lf ", &stu->id, &stu->sex,
        &stu->age, stu->name, &stu->high, &stu->weight);
}

// 简单打印数据
static void _student_print(struct student* stu) {
    static int _idx;

    printf("%d: %d %c %d %s %lf %lf \n", _idx++, stu->id,
        stu->sex, stu->age, stu->name, stu->high, stu->weight);
}

/*
 * 一种最简单的通用序列化方法
 */
int main(int argc, char* argv[]) {

    FILE* txt = fopen(_STR_TXT, "wb+");
    if (NULL == txt) {
        fprintf(stderr, "fopen " _STR_TXT " error!\n");
        return -1;
    }

    // 这里写入数据
    struct student stu = { 0, 0, 23, "鸣人", 172.23, 64.05 };
    _student_print(&stu);

    // 这里序列化并写入数据到文件
    _student_serialize(&stu, txt);

    // 我们读取这个文件, 先设置文件指针到文件开头
    fseek(txt, 0, SEEK_SET);

    // 开始读取数据
    struct student ts;
    _student_deserialize(&ts, txt);
    _student_print(&ts);

    fclose(txt);
    system("pause");
    return 0;
}

 

实质在  自定义编码解码,并选用 scanf和printf 对映关系

// struct student 结构体序列化到文件的方法
static void _student_serialize(struct student* stu, FILE* txt) {
    fprintf(txt, "%d %c %d %s %lf %lf ", stu->id, stu->sex, 
        stu->age, stu->name, stu->high, stu->weight);
}

// struct student 结构体反序列化
static void _student_deserialize(struct student* stu, FILE* txt) {
    fscanf(txt, "%d %c %d %s %lf %lf ", &stu->id, &stu->sex,
        &stu->age, stu->name, &stu->high, &stu->weight);
}

 

运转结果 如下:

json 1

通过那种达成, 是跨平台的. 因为C完毕正式和和谐定义协议辅助

 "%d %c %d %s %lf %lf "

 

最终我们还会谈论那种景况.

 

正文

1. 3回失利扩充 fscanf -> fread ; fprintf -> fwrite

测试如下, 在window上测试代码 main.c

json 2json 3

#include <stdio.h>
#include <stdlib.h>

#define _INT_NAME        (64)
#define _STR_TXT        "student.struct"

struct student {
    int id;
    char sex;
    int age;
    char name[_INT_NAME + 1];
    double high;
    double weight;
};

// struct student 结构体序列化到文件的方法
static void _student_serialize(struct student* stu, FILE* txt) {
    fwrite(stu, sizeof(*stu), 1, txt);
}

// struct student 结构体反序列化
static void _student_deserialize(struct student* stu, FILE* txt) {
    fread(stu, sizeof(*stu), 1, txt);
}

// 简单打印数据
static void _student_print(struct student* stu) {
    static int _idx;

    printf("%d: %d %c %d %s %lf %lf \n", _idx++, stu->id,
        stu->sex, stu->age, stu->name, stu->high, stu->weight);
}

/*
* 一种最简单的通用序列化方法
*/
int main(int argc, char* argv[]) {
    FILE* txt = fopen(_STR_TXT, "wb+");
    if (NULL == txt) {
        fprintf(stderr, "fopen " _STR_TXT " error!\n");
        return -1;
    }

    // 这里写入数据
    struct student stu = { 0, 0, 23, "鸣人", 172.23, 64.05 };
    _student_print(&stu);

    // 这里序列化并写入数据到文件
    _student_serialize(&stu, txt);

    // 我们读取这个文件, 先设置文件指针到文件开头
    fseek(txt, 0, SEEK_SET);

    // 开始读取数据
    struct student ts;
    _student_deserialize(&ts, txt);
    _student_print(&ts);

    fclose(txt);
    system("pause");
    return 0;
}

View Code

 

核心是 

// struct student 结构体序列化到文件的方法
static void _student_serialize(struct student* stu, FILE* txt) {
    fwrite(stu, sizeof(*stu), 1, txt);
}

// struct student 结构体反序列化
static void _student_deserialize(struct student* stu, FILE* txt) {
    fread(stu, sizeof(*stu), 1, txt);
}

 

 在 linux 上拍卖的代码 是 serialize.c

#include <stdio.h>
#include <stdlib.h>

#define _INT_NAME       (64)
#define _STR_TXT        "student.struct"

struct student {
    int id; 
    char sex;
    int age;
    char name[_INT_NAME + 1]; 
    double high;
    double weight;
};

// struct student 结构体反序列化
static void _student_deserialize(struct student* stu, FILE* txt) {
    fread(stu, sizeof(*stu), 1, txt);
}

// 简单打印数据
static void _student_print(struct student* stu) {
    static int _idx;

    printf("%d: %d %c %d %s %lf %lf \n", _idx++, stu->id,
        stu->sex, stu->age, stu->name, stu->high, stu->weight);
}

/*
 * 处理 window 上生成的内存文件, 看是否跨平台
 */
int main(int argc, char* argv[]) {
    // 这里就简单读取 _STR_TXT
    FILE* txt = fopen(_STR_TXT, "rt");
    if (NULL == txt) {
        fprintf(stderr, "fopen " _STR_TXT " error!\n");
        return -1; 
    }   

    // 开始读取数据
    struct student ts; 
    _student_deserialize(&ts, txt);

    // 打印读取数据测试
    _student_print(&ts);

    fclose(txt);
    return 0;
}

 

编写翻译 命令的是

gcc -g -Wall -o serialize.out serialize.c

 

将 window生成的 student.struct 文件传输到linux测试机上, 运维结果 如下:

json 4

时期开始展览了各样横祸

a. 考虑转码

b. 考虑 fopen 创建utf8 文件

c. 考虑代码转码

…….

照旧以退步告终, 预计fread, fwrite是差异平台的直接内部存款和储蓄器文件. 差距大,
不符合跨平台, 可是同样平台是比较快的设想方式.

扩充一下, 怎么获得文件字符长度

linux得到文件长度扩展 
http://blog.csdn.net/yutianzuijin/article/details/27205121

 

2. 选取 protobuf – c google一种协议.

pbc 传输协议, 很多公司都在使用, 作者看了一晃, 网上贯彻版本相比较多,
以往大概有官方版本了. 推荐一个

cloudwn pbc
https://github.com/cloudwu/pbc 

或是是最精简的一种完毕, 源码写的很好, 可是觉得有点复杂了.
为了那样成效这么搞, 没意思.

最关键的是 pbc 需求转移中间协议文件,  占用内部存款和储蓄器也不少.

那也是一种缓解方案.

 

3. 采用json协议

本条意思很精晓, 大家都经过json来处理难点 那里推荐自身写的四个json引擎

C json实战引擎 一 ,
达成解析部分

C json实战引擎 二 ,
完毕结构部分

C json实战引擎 三 ,
最终达成部分帮衬函数

源码在一千行左右,欢迎使用. 那也是一种缓解方案. 近来和爱侣在议论难题,
特别觉得,  总计机软件开发无非

围绕 空间和岁月来回搞,  通用还是针对.

真实性生产条件中恐怕会更直白些, 快些, 没bug就行, 怎么爽怎么随便,
怎么快怎么来. 哈哈.

可是对于C,  还是有一套本身的历史学, 用最简易实现一场意外.  C/C++ 老了,
但却是美的.

那种化解方案讲到那里了.

 

4. 启幕便是截至. 还是从最简便的起始. 完毕1个C 体系换流程

末端继续教师通过 fscanf 和 fprintf 营造 C的行列化. 先看一种完结体,
serialize_student.h

#ifndef _H_SERIALIZE_THREE_SERIALIZE_STUDENT
#define _H_SERIALIZE_THREE_SERIALIZE_STUDENT

#include <assert.h>
#include <stdio.h>
#include <limits.h>

// 1.0 定义序列换结构体
#define _INT_NAME        (64)
struct student {
    int id;
    char sex;
    int age;
    char name[_INT_NAME + 1];
    double high;
    double weight;
};

// 2.0 定义保存文件交换文件名 当前文件名去掉 .h
#define    _STR_SERIALIZE_TXT_student    "serialize_student"

//3.0 定义转换读取协议, printf协议后面跟' ', printf后面跟的, scanf跟的
#define    _STR_SERIALIZE_PBC_student    "%d %c %d %s %lf %lf "
#define _F_SERIALIZE_PRINTF_student(p) \
    p->id, p->sex, p->age, p->name, p->high, p->weight
#define _F_SERIALIZE_SCANF_student(p) \
    &p->id, &p->sex, &p->age, p->name, &p->high, &p->weight

// 3.0 定义序列换数据写入方法
static int serialize_student_printfs(void* data, int len) {
    assert(data && len > 0);

    FILE* txt = fopen(_STR_SERIALIZE_TXT_student, "wb");
    if (!txt) return -1;

    struct student* p = data;
    for (int i = 0; i < len; ++i) {
        fprintf(txt, _STR_SERIALIZE_PBC_student, _F_SERIALIZE_PRINTF_student(p));
        ++p;
    }

    fclose(txt);
    return 0;
}

// 4.0 定义序列化数据读取方法
static int serialize_student_scanfs(void* data, int len) {
    assert(data);

    FILE* txt = fopen(_STR_SERIALIZE_TXT_student, "rb");
    if (!txt) return -1;

    int ns = 0;
    struct student* p = data;
    int nz = 0;
    const char* s = _STR_SERIALIZE_PBC_student;
    while (*s) {
        if (*s == '%')
            ++nz;
        ++s;
    }

    while (ns < len && fscanf(txt, _STR_SERIALIZE_PBC_student, _F_SERIALIZE_SCANF_student(p)) == nz) {
        ++ns;
        ++p;
    }

    fclose(txt);
    return ns;
}


#endif // !_H_SERIALIZE_THREE_SERIALIZE_STUDENT

 

 那里看看注释不难领会, 那里教书一下 头文件导入宏规则.

_H 开头 + _项目名 + _文件名(去掉后缀) 
首要为了缓解项目专门多的时候联编造成宏碰撞.

测试代码 main.c

#include <stdlib.h>
#include "serialize_student.h"

/*
 * 实现C的序列流程操作
 */
int main(int argc, char* argv[]) {

    struct student stu[] = { 
        { 0, 0, 23, "鸣人", 172.23, 64.05 },
        { 0, 0, 34, "杀生丸", 178.23, 74.00 } 
    };

    // 先序列化到文件
    serialize_student_printfs(stu, sizeof(stu) / sizeof(*stu));

    // 开始读取序列化内容
    struct student sts[2];
    serialize_student_scanfs(sts, 2);

    for (int i = 0; i < 2; ++i) {
        printf("%d => %s\n", i, sts[i].name);
    }

    puts("你喜欢吗, ... ");

    system("pause");
    return 0;
}

json, 

 运维结果是

json 5

最终可能来点 封装, 收缩事后的行事量. 大概有点复杂, 直接看代码,
能掌握就呵呵一笑而过.

再公布前面封装在此以前讲三个小知识, linux 上宏调节和测试有个小技巧 通过 gcc -E
导出 *.i 文件, 查看宏命令.

同一 window 上 vs 须要这么
设置json 6

丰硕 /EP /P 运转时候会生成 main.i

json 7

找到难题后再将其去掉. 编写翻译运维.

我们先看二个 C宏模板 系列化注册头文件 serialize-base.h

#ifndef _H_SERIALIZE_THREE_SERIALIZE_BASE
#define _H_SERIALIZE_THREE_SERIALIZE_BASE

#include <assert.h>
#include <stdio.h>
#include <limits.h>

/*
 * 宏模板, 为想实现序列化的结构注册函数
 * name    : 结构名称,                例如 student
 * pbc    : 定义的协议,                例如 "%d %c %d %s %lf %lf "
 * ptf    : printf 打印数据参数集,    例如 _->id, _->sex, _->age, _->name, _->high, _->weight | SERIALIZE_PTF
 * scf    : scanf 得到数据的参数集,    例如 &_->id, &_->sex, &_->age, _->name, &_->high, &_->weight | SERIALIZE_SCF
 */
#define SERIALIZE_BASE_REGISTER(name, pbc, ptf, scf)                                \
static int serialize_printfs_##name(void* data, int len) {                            \
    assert(data && len > 0);                                                        \
                                                                                    \
    FILE* txt = fopen("serialize_"#name, "wb");                                        \
    if (!txt) return -1;                                                            \
                                                                                    \
    struct name* _ = (struct name*)data;                                            \
    for (int i = 0; i < len; ++i) {                                                    \
        fprintf(txt, pbc, ptf);                                                    \
        ++_;                                                                        \
    }                                                                                \
                                                                                    \
    fclose(txt);                                                                    \
    return 0;                                                                        \
}                                                                                    \
                                                                                    \
static int serialize_scanfs_##name(void* data, int len) {                            \
    assert(data);                                                                    \
                                                                                    \
    FILE* txt = fopen("serialize_"#name, "rb");                                        \
    if (!txt) return -1;                                                            \
                                                                                    \
    int ns = 0, nz = 0;                                                                \
    struct name* _ = (struct name*)data;                                            \
    const char* s = pbc;                                                            \
    while (*s) {                                                                    \
        if (*s == '%')                                                                \
            ++nz;                                                                    \
        ++s;                                                                        \
    }                                                                                \
                                                                                    \
    while (ns < len && fscanf(txt, pbc, scf) == nz) {                            \
        ++ns;                                                                        \
        ++_;                                                                        \
    }                                                                                \
                                                                                    \
    fclose(txt);                                                                    \
    return ns;                                                                        \
}                                                                                    \


#endif // !_H_SERIALIZE_THREE_SERIALIZE_BASE

 

背后写四个构造 来落实种类化 serialize_person.h

#ifndef _H_SERIALIZE_THREE_SERIALIZE_PERSON
#define _H_SERIALIZE_THREE_SERIALIZE_PERSON

// 必须导入(继承) 序列化基础实现模板
#include "serialize-base.h"

// 1.0 定义序列换结构体
struct person {
    int id;
    char sex;
    int age;
    char name[65];
    double high;
    double weight;
};

// 2.0 注册得到 ptf 结构
#undef    SERIALIZE_PTF
#define SERIALIZE_PBC(id, sex, age, name, high, weight) \
    _->id, _->sex, _->age, _->name, _->high, _->weight

// 3.0 注册得到 sct 结构
#undef    SERIALIZE_SCF
#define SERIALIZE_SCF(id, sex, age, name, high, weight) \
    &_->id, &_->sex, &_->age, _->name, &_->high, &_->weight

// 4.0 最后开始注册实现体
SERIALIZE_BASE_REGISTER(
    person,
    "%d %c %d %s %lf %lf ",
    SERIALIZE_PBC(id, sex, age, name, high, weight), 
    SERIALIZE_SCF(id, sex, age, name, high, weight)
)

#endif // !_H_SERIALIZE_THREE_SERIALIZE_PERSON

 

是还是不是很酷炫, 好测试一下 main.c

#include <stdlib.h>
#include "serialize_student.h"
#include "serialize_person.h"

/*
 * 实现C的序列流程操作
 */
int main(int argc, char* argv[]) {

    struct student stu[] = { 
        { 0, 0, 23, "鸣人", 172.23, 64.05 },
        { 1, 0, 34, "杀生丸", 178.23, 74.00 } 
    };

    // 先序列化到文件
    serialize_student_printfs(stu, sizeof(stu) / sizeof(*stu));

    // 开始读取序列化内容
    struct student sts[2];
    serialize_student_scanfs(sts, 2);

    for (int i = 0; i < 2; ++i) {
        printf("%d => %s\n", i, sts[i].name);
    }

    puts("你喜欢吗, ... ");


    struct person ps[] = {
        { 2, 1, 23, "日向雏田", 162.23, 51.05 },
        { 3, 1, 14, "玲", 158.23, 45.00 }
    };

    // 序列化数据
    serialize_printfs_person(ps, sizeof(ps) / sizeof(*ps));
    // 得到序列化数据

    struct person tps[2];
    serialize_scanfs_person(tps, 2);

    for (int i = 0; i < 2; ++i) {
        printf("%d => %s\n", i, sts[i].name);
    }

    system("pause");
    return 0;
}

 

测试结果如下, 一切符合规律

json 8

 到那边基本都得了了. 首要着力便是上面注册的函数模板.

 

后记

这一次后记大家在linux上测试一下 将刚生成的 serialize_person 上传到
linux平台

测试文件 main.c

#include <stdlib.h>
#include "serialize_person.h"

/*
 * 实现C的序列流程操作
 */
int main(int argc, char* argv[]) {

    puts("Play time game, writing code");

    struct person tps[2];
    serialize_scanfs_person(tps, 2); 

    for (int i = 0; i < 2; ++i) {
        printf("%d => %s\n", i, tps[i].name);
    }   

    return 0;
}

 

说到底测试结果

json 9

源码成功, 到那边差不离能够离开了.

至于C数据体系化的粗略操作就到此地了.    错误是免不了的, 拜~~~

 

相关文章

网站地图xml地图