数据格式-个人整理

在整理代码时想到是否有比JSON更好的数据格式没有,然后就了解当下有哪些数据格式。

1.自定义二进制  

        要自己实现,有开发维护需求, 专业度高;效率高。

2.提供序列化和反序列化库的开源协议 

        【如protocol buffers,Thrift】;

        引入第三方库,        

3.文本化协议 

        【如json,xml】 

        传输效率低

 

-----------------------------------------------------------

2024年7月25日  15点05分 ,今天先整理到这,如下已经满足大部分开发使用了

----------------------------------------------------------

数据格式
  1. YAML (YAML Ain't Markup Language): YAML 是一种直观的数据序列化格式,旨在使人类编写和阅读数据变得容易。它使用空白和缩进来表示层次结构,这使得 YAML 文件通常比 JSON 文件更易于阅读和编写。
  2. TOML (Tom's Obvious, Minimal Language): TOML 是另一种轻量级的配置文件格式,设计用于易于阅读和编写。它支持基本的数据类型以及数组和表格,并且具有明确的语法,这使得它非常适合配置文件。
  3. XML (eXtensible Markup Language): XML 是一种标记语言,用于结构化文档和数据。虽然它通常比 JSON 或 YAML 更冗长,但它提供了丰富的结构和命名空间支持,使其在某些领域仍然很受欢迎。
  4. CSV (Comma-Separated Values): CSV 是一种简单的平面文件格式,用于存储表格数据。它非常适合存储和传输数据集,但不适合复杂的嵌套数据结构。
  5. Protocol Buffers: Protocol Buffers 是 Google 开发的一种高效的数据交换格式,它使用二进制格式,因此在传输和解析速度上优于文本格式。虽然它不如 JSON 或 YAML 人性化,但在性能敏感的应用中非常有用。
  6. MessagePack: MessagePack 是一种高效的二进制序列化格式,类似于 Protocol Buffers,但不需要显式的模式定义。它支持多种语言,并且在许多情况下比 JSON 更紧凑。
  7. Properties (Java Properties Format): 这是一种简单的键值对格式,主要用于 Java 应用程序的配置文件。它使用等号 (=) 分隔键和值,使用井号 (#) 表示注释。
  8. 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;

参考文章:

1. 一种简易网络传输数据格式【替代json/xml】_类似json的数据格式-CSDN博客

2. 替代JSON-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值