在整理代码时想到是否有比JSON更好的数据格式没有,然后就了解当下有哪些数据格式。
1.★自定义二进制
要自己实现,有开发维护需求, 专业度高;效率高。
2.★提供序列化和反序列化库的开源协议
【如protocol buffers,Thrift】;
引入第三方库,
3.★文本化协议
【如json,xml】
传输效率低
-----------------------------------------------------------
2024年7月25日 15点05分 ,今天先整理到这,如下已经满足大部分开发使用了
----------------------------------------------------------
数据格式
- ★YAML (YAML Ain't Markup Language): YAML 是一种直观的数据序列化格式,旨在使人类编写和阅读数据变得容易。它使用空白和缩进来表示层次结构,这使得 YAML 文件通常比 JSON 文件更易于阅读和编写。
- ★TOML (Tom's Obvious, Minimal Language): TOML 是另一种轻量级的配置文件格式,设计用于易于阅读和编写。它支持基本的数据类型以及数组和表格,并且具有明确的语法,这使得它非常适合配置文件。
- ★XML (eXtensible Markup Language): XML 是一种标记语言,用于结构化文档和数据。虽然它通常比 JSON 或 YAML 更冗长,但它提供了丰富的结构和命名空间支持,使其在某些领域仍然很受欢迎。
- ★CSV (Comma-Separated Values): CSV 是一种简单的平面文件格式,用于存储表格数据。它非常适合存储和传输数据集,但不适合复杂的嵌套数据结构。
- ★Protocol Buffers: Protocol Buffers 是 Google 开发的一种高效的数据交换格式,它使用二进制格式,因此在传输和解析速度上优于文本格式。虽然它不如 JSON 或 YAML 人性化,但在性能敏感的应用中非常有用。
- ★MessagePack: MessagePack 是一种高效的二进制序列化格式,类似于 Protocol Buffers,但不需要显式的模式定义。它支持多种语言,并且在许多情况下比 JSON 更紧凑。
- ★Properties (Java Properties Format): 这是一种简单的键值对格式,主要用于 Java 应用程序的配置文件。它使用等号 (=) 分隔键和值,使用井号 (#) 表示注释。
- ★INI Files: INI 文件格式是一种简单的配置文件格式,使用节和键值对。它被广泛用于 Windows 应用程序的配置文件。
9. Avro
Avro,是指数据序列化的系统,有丰富的数据结构类型、快速可压缩的二进制数据形式。
当Avro数据存储到文件中时,它的模式也随之存储,这样任何程序都可以对文件进行处理。
Avro依赖于模式(Schema)。Avro数据的读写操作是很频繁的,而这些操作都需要使用模式,这样就减少写入每个数据资料的开销,使得序列化快速而又轻巧。这种数据及其模式的自我描述方便于动态脚本语言的使用。
Avro模式是用JSON(一种轻量级的数据交换模式)定义的,这样对于已经拥有JSON库的语言可以容易实现。
原文链接: Avro_百度百科
10.★Thrift
Thrift包含一套完整的栈来创建客户端和服务端程序。顶层部分是由Thrift定义生成的代码。而服务则由这个文件客户端和处理器代码生成。在生成的代码里会创建不同于内建类型的数据结构,并将其作为结果发送。协议和传输层是运行时库的一部分。有了Thrift,就可以定义一个服务或改变通讯和传输协议,而无需重新编译代码。除了客户端部分之外,Thrift还包括服务器基础设施来集成协议和传输,如阻塞、非阻塞及多线程服务器。栈中作为I/O基础的部分对于不同的语言则有不同的实现。
Thrift支持众多通讯协议:
TBinaryProtocol – 一种简单的二进制格式,简单,但没有为空间效率而优化。比文本协议处理起来更快,但更难于调试。
TCompactProtocol – 更紧凑的二进制格式,处理起来通常同样高效。
TDebugProtocol – 一种人类可读的文本格式,用来协助调试。
TDenseProtocol – 与TCompactProtocol类似,将传输数据的元信息剥离。
TJSONProtocol – 使用JSON对数据编码。
TSimpleJSONProtocol – 一种只写协议,它不能被Thrift解析,因为它使用JSON时丢弃了元数据。适合用脚本语言来解析。
支持的传输协议有:
TFileTransport – 该传输协议会写文件。
TFramedTransport – 当使用一个非阻塞服务器时,要求使用这个传输协议。它按帧来发送数据,其中每一帧的开头是长度信息。
TMemoryTransport – 使用存储器映射输入输出。(Java的实现使用了一个简单的ByteArrayOutputStream。)
TSocket – 使用阻塞的套接字I/O来传输。
TZlibTransport – 用zlib执行压缩。用于连接另一个传输协议。
Thrift还提供众多的服务器,包括:
TNonblockingServer – 一个多线程服务器,它使用非阻塞I/O(Java的实现使用了NIO通道)。TFramedTransport必须跟这个服务器配套使用。
TSimpleServer – 一个单线程服务器,它使用标准的阻塞I/O。测试时很有用。
TThreadPoolServer – 一个多线程服务器,它使用标准的阻塞I/O
原文链接: thrift_百度百科
自定义二进制-简易参考代码
一种简易网络传输数据格式【替代json/xml】_类似json的数据格式-CSDN博客
提供一种简单的key-val数据封装,无需引入库,仅仅是一个简单的类,传输效率效率远高于第3种方式。名为 DatX。
DatX一定程度上只是提供了一种方案,起抛砖引玉的作用,但同时此处提供的DatX代码也是一个完整的,可直接引入工程使用的类。
如果愿意使用,请保留类注释中的作者笔名[hicker]^_^
注意:由于未使用算法优化内存的分配,故每调用一次Put都会重新malloc/free内存。有必要可以自己实现一个内存分配算法
主要接口:
// 添加数据
BOOL Put(char *szKey, int iVal);
BOOL Put(char *szKey, float fVal);
BOOL Put(char *szKey, void *pData, int nData);
// 反序列化
BOOL UnPack(void *pData, int nData);
// 获取第i个key名
char *GetKey(int i);
// 获取key所对应的val,类型为xty
xty operator[](int i);
xty operator[](char *szKey);
// 将返回DatX数据的二进制流,以及大小
void *Bytes();
int Total();代码如下,只有一个结构体DatX
DatX.h
/************************************************************************* ** Desc : 为避免使用json和xml做网络传输,实现一种简单key-val数据类型, ** 内存结构如下: [cnt|int_key|xty_key|int_dat|xty|xty_dat] ** cnt_seg: 数据个数段,iCnt,xCnt ** int_key_seg: int/float型key ** xty_key_seg: xty型key ** int_dat: int型数据区 ** xty: xty区 ** xty_dat: xty.p的数据区 ** 【注意】DatX会自动将int型key/val保存在xty型key/val前 ** Author : hicker@2017-3-19 11:11:57 *************************************************************************/ typedef struct tagDatX { tagDatX() :iCnt(0), xCnt(0), __p(NULL), __n(sizeof(iCnt) + sizeof(xCnt)), __p_cnt(NULL), __p_int_key(NULL), __p_xty_key(NULL), __p_int_dat(NULL), __p_xty(NULL), __p_xty_dat(NULL), __z_xty_dat(0){} tagDatX(void *pData, int nData) :iCnt(0), xCnt(0), __p(NULL), __n(sizeof(iCnt) + sizeof(xCnt)), __p_cnt(NULL), __p_int_key(NULL), __p_xty_key(NULL), __p_int_dat(NULL), __p_xty(NULL), __p_xty_dat(NULL), __z_xty_dat(0) { UnPack(pData, nData); } ~tagDatX(){ if (__p) free((void*)__p); } typedef struct tagxty { tagxty():p(NULL),l(0){} char *ToChar(int *nLen = 0){ if (nLen)*nLen = l; return (char*)p; }; int ToInt(){ return l; }; float ToFloat(){ return *((float*)&l); }; private: int p; // xty数据内存偏移量 int l; // xty数据大小 friend tagDatX; }xty; BOOL Put(char *szKey, int iVal) { // 保存旧偏移 save_old_ofs(); // 申请新内存 __n += __z_k + __z_i; __p = (int)malloc(__n); if (__p == NULL) { __p = __p_old; __n = __n_old; return FALSE; } memset((void*)__p, 0, __n); iCnt++; // 计算新偏移量 calc_new_ofs(); // __z_xty_dat; // 保存旧数据 if (__p_old) save_old_dat(); // 保存新数据 ((int*)__p_cnt)[0] = iCnt; ((int*)__p_cnt)[1] = xCnt; strcpy((char*)(__p_int_key + iCnt_old*__z_k), szKey); *(int*)(__p_int_dat + iCnt_old*__z_i) = iVal; return TRUE; } BOOL Put(char *szKey, float fVal) { return Put(szKey, *(int*)&fVal); } BOOL Put(char *szKey, void *pData,int nData) { // 保存旧偏移 save_old_ofs(); // 申请新内存 __n += __z_k + __z_c+nData; __p = (int)malloc(__n); if (__p == NULL) { __p = __p_old; __n = __n_old; return FALSE; } memset((void*)__p, 0, __n); xCnt++; // 计算新偏移量 calc_new_ofs(); __z_xty_dat +=nData; // 保存旧数据 if (__p_old) save_old_dat(); // 保存新数据 ((int*)__p_cnt)[0] = iCnt; ((int*)__p_cnt)[1] = xCnt; strcpy((char*)(__p_xty_key + xCnt_old*__z_k), szKey); ((int*)(__p_xty + __z_x*xCnt_old))[0] = __z_xty_dat_old; ((int*)(__p_xty + __z_x*xCnt_old))[1] = nData; memcpy((void*)(__p_xty_dat + __z_xty_dat_old), pData, nData); return TRUE; } BOOL UnPack(void *pData, int nData) { // 保存旧偏移 save_old_ofs(); // 申请新内存 __n = nData; __p = (int)malloc(__n); if (__p == NULL) { __p = __p_old; __n = __n_old; return FALSE; } memcpy((void*)__p, pData, __n); // 解析 iCnt,xCnt iCnt = ((int*)__p)[0]; xCnt = ((int*)__p)[1]; // 计算新偏移量 calc_new_ofs(); // 解析__z_xty_dat for (int i = iCnt; i < iCnt + xCnt; i++) __z_xty_dat += ((int*)(__p_xty + i*__z_x))[1];//((*this)[i]).l; return TRUE; } char *GetKey(int i) { if (i < iCnt + xCnt) { return (char*)(__p_int_key + (i*__z_k)); } return NULL; }; xty operator[](int i) { xty x; if (i < iCnt) { x.l = *(int*)(__p_int_dat + (i*__z_i)); } else if (i < iCnt + xCnt) { //memcpy(&x, (void*)(__p_xty+((i-iCnt)*__z_x)), __z_x); x.p = ((int*)(__p_xty + ((i - iCnt)*__z_x)))[0]; x.l = ((int*)(__p_xty + ((i - iCnt)*__z_x)))[1]; x.p += __p_xty_dat; } return x; } xty operator[](char *szKey) { xty x; for (int i = 0; i < iCnt+xCnt; i++) { if (strcmp(szKey, (char*)(__p_int_key + (i*__z_k))) == 0) return (*this)[i]; } return x; } void *Bytes(){ return (void*)__p; } int Total(){ return __n; } private: void save_old_ofs() {// 保存旧偏移 __p_old = __p; __n_old = __n; __p_cnt_old = __p_cnt; __p_int_key_old = __p_int_key; __p_xty_key_old = __p_xty_key; __p_int_dat_old = __p_int_dat; __p_xty_old = __p_xty; __p_xty_dat_old = __p_xty_dat; __z_xty_dat_old = __z_xty_dat; iCnt_old = iCnt; xCnt_old = xCnt; } void save_old_dat() {// 保存旧数据 memcpy((void*)__p_cnt, (void*)__p_cnt_old, __z_c); memcpy((void*)__p_int_key, (void*)__p_int_key_old, __z_k*iCnt_old); memcpy((void*)__p_xty_key, (void*)__p_xty_key_old, __z_k*xCnt_old); memcpy((void*)__p_int_dat, (void*)__p_int_dat_old, __z_i*iCnt_old); memcpy((void*)__p_xty, (void*)__p_xty_old, __z_x*xCnt_old); memcpy((void*)__p_xty_dat, (void*)__p_xty_dat_old, __z_xty_dat_old); free((void*)__p_old); } void calc_new_ofs() { // 计算新偏移量 __p_cnt = __p; __p_int_key = __p_cnt + __z_c; __p_xty_key = __p_int_key + __z_k*iCnt; __p_int_dat = __p_xty_key + __z_k*xCnt; __p_xty = __p_int_dat + __z_i*iCnt; __p_xty_dat = __p_xty + __z_x*xCnt; } public: int iCnt; // int/float 个数 int xCnt; // xty 个数 private: static const int __z_k = 32; // szKey最大长度 static const int __z_c = sizeof(int) * 2; // 头大小[sizeof(iCnt) + sizeof(xCnt);] static const int __z_i = sizeof(int); // int大小 static const int __z_x = sizeof(int) * 2; // xty大小[sizeof(xty::p)+sizeof(xty::l)] // 各数据段偏移量 int __p_cnt; int __p_int_key; int __p_xty_key; int __p_int_dat; int __p_xty; int __p_xty_dat; int __z_xty_dat; // 各数据段old偏移量 int __p_old ; int __n_old; int __p_cnt_old; int __p_int_key_old; int __p_xty_key_old; int __p_int_dat_old; int __p_xty_old; int __p_xty_dat_old; int __z_xty_dat_old; int iCnt_old; int xCnt_old; int __p; // 内存起始地址 int __n; // 内存中的大小 }DatX;
参考文章: