zoukankan      html  css  js  c++  java
  • 二进制配置文件为什么比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进行二进制文件读写 

    FormatC TypePython字节数
    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 

     

    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++读二进制文件

    #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;
    }

    结果为

  • 相关阅读:
    Luogu 3119 [USACO15JAN]草鉴定Grass Cownoisseur
    Luogu 4514 上帝造题的七分钟
    Luogu 1484 种树
    Luogu【P2904】跨河(DP)
    Luogu【P2065】贪心的果农(DP)
    Luogu【P1725】琪露诺(单调队列,DP)
    二分图匹配
    单调队列
    Tarjan的强联通分量
    手写堆
  • 原文地址:https://www.cnblogs.com/BigFeng/p/5003904.html
Copyright © 2011-2022 走看看