二进制配置文件为什么比json等配置文件效率高
二进制配置文件为什么比json等配置文件高效
项目中用spine做动画,spine可以导出json和二进制的动画配置文件,蛋疼的是spine官方竟然没有提供c的二进制配置解析代码,更没有提供它二进制文件的格式说明。为了动画加载的更快,只能自己把json用python转成二进制文件(格式自定),再自行实现解析二进制的c代码了。经过小心谨慎的代码实现后,测试结果是二进制配置文件比json文件大小小了1半以上,并且动画创建速度快1倍以上。下文简单总结了一下二进制配置文件的优点。
1.什么是二进制配置文件
当然,一切文件在计算机中都是以二进制(01)格式存储的,那么二进制配置文件是指什么呢?比如要存储
{ "time" = 133, "color" = [233, 0, 0], "pos" = [34, 22] }
json一般以utf-8格式保存成文本,那么什么是utf-8呢?它是unicode编码的一种实现形式,具体解释请参考UTF-8编码规则(转),中日韩uincode编码参考。也就是说,像程序中的数字类型133,233,22等,一个uint8就能存储下了,可是133在json中却占了3个字节,要是存个12.432312等数据要占用更多的空间。而本文所说的二进制配置,直接存133等的uint8二进制编码0x85,这样便减少了一部分文件大小。编码与解码可以商量好,比如time,编解码都以t代替,又可以节省一部分空间,甚至可以不存储time,color,pos等key,直接顺序在配置中写value,解码时直接读value(为了说的清楚,后面的例子保留了key)这样又可以减少配置文件的大小。
2.二进制配置文件优点与缺点
优点已经说了,2个优点:文件小、解析快。为啥文件小上面已经说了。至于为啥解析快呢,首先,因为文件小,io时间需要的就少。其次,少了把配置文件解析成json对象或xml对象的中间步骤,直接读这个二进制文件就可以,我觉得顺着读二进制文件可以达到最快的速度。
缺点也有2个:难以直接查看、通用性差。json或xml等配置文件可以直接看出来配置的是神马,可是这个二进制就啥也看不出来了。通用性差是因为要达到高效的解析,最好顺着解析,捋一遍配置文件就完了,所以解析二进制的代码难以公用。
3.读写二进制例子
比如上面的那个json文件,怎么搞成二进制配置呢,可以先规定好数据的类型,比如s为string,i为number,f为float。string还要告诉解析时字符串有多长,比如time就是s4time。上面的例子要写二进制就是s4timei133s5colori244i0i0s3posi34i22,这肯定不是最优的,就是为了说明怎么读写二进制而已。
(1)python写二进制文件
python写二进制文件用到了 struct.pack,读二进制用 struct.unpack(),具体怎用用struct请参考 使用Python进行二进制文件读写
Format | C Type | Python | 字节数 |
---|---|---|---|
x | pad byte | no value | 1 |
c | char | string of length 1 | 1 |
b | signed char | integer | 1 |
B | unsigned char | integer | 1 |
? | _Bool | bool | 1 |
h | short | integer | 2 |
H | unsigned short | integer | 2 |
i | int | integer | 4 |
I | unsigned int | integer or long | 4 |
l | long | integer | 4 |
L | unsigned long | long | 4 |
q | long long | long | 8 |
Q | unsigned long long | long | 8 |
f | float | float | 4 |
d | double | float | 8 |
s | char[] | string | 1 |
p | char[] | string | 1 |
P | void * | long |
1 2 3 4 5 6 7 8 9 10 11 12 | import struct def writeBinary(): binaryFile = open (r "./binary.obj" , "wb" ); binaryFile.write(struct.pack( "i" , 4 )); binaryFile.write(struct.pack( "4s" , "time" )); binaryFile.write(struct.pack( "i" , 133 )); binaryFile.write(struct.pack( "i" , 5 )); binaryFile.write(struct.pack( "5s" , "color" )); if __name__ = = "__main__" : writeBinary(); |
执行完会产生下面的二进制文件
(2)c++读二进制文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | #include <iostream> using namespace std; char * data = nullptr ; char * getFileContent( const char * filePath) { FILE *pFile= fopen (filePath, "r" ); char * pBuf; fseek (pFile, 0, SEEK_END); int len = ftell (pFile); pBuf = new char [len+1]; rewind (pFile); fread (pBuf, 1, len, pFile); pBuf[len] = 0; fclose (pFile); return pBuf; } int8_t readByte() { return (int8_t)*data++; } int32_t readInt() { int32_t val = 0; char * pd = ( char *)&val; *pd = readByte(); *(pd + 1) = readByte(); *(pd + 2) = readByte(); *(pd + 3) = readByte(); return (int32_t)val; } std::string readString() { int32_t strLen = readInt(); std::string str = std::string(data, strLen); data = data + strLen; return str; } int main() { data = getFileContent( "/Users/abc/PycharmProjects/BinaryTest/binary.obj" ); std::string timeStr = readString(); int timeValue = readInt(); std::string colorStr = readString(); std::cout << "timeStr is " << timeStr << std::endl; std::cout << "colorStr is " << colorStr << std::endl; std::cout << "timeValue is " << timeValue << std::endl; free (data); return 0; } |
结果为
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具