利用C一种最有效的文件存储方式——16bit有符号位2进制存储

Posted sunguiy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了利用C一种最有效的文件存储方式——16bit有符号位2进制存储相关的知识,希望对你有一定的参考价值。

2020年7月6日  23:17:31

环境:VS2013   C语言

 

最近在处理一些较大的数据,今天想要将一组超过百G的信号采集数据进行信号处理后,在重新存储起来,作为后续程序的起始数据。

在看了网上诸多的什么比如用类人算的方法将整数拆解为2进制、直接存储整数格式等建议之后,我感觉这些都不是我想要的。

受到读取数据16bit有符号数据的启发:(如下,小端模式)

技术图片

我也想将存储的数据也得到类似于此的性能,即存储数据的大小SizeF严格遵循

SizeF = 2(Byte)* Fs * t

其中Fs为采样率,t为采样时间。

但是使用整形数据直接储存或16进制直接储存并不能满足。

最后我将本问题的解决方案定为:也就是想要读取一组格式为小端模式的16bit有符号数据,并将其进行信号处理后,重新以最有效的16bit有符号数据格式存储(大端模式)起来。。最后也实现了。

一开始的测试,用了一个大小(393750kB)的原数据做例子:

技术图片

以上为测试的结果,从上到下分别以5位整数(%5d)、4位16进制(%04x)以及16位2进制的不同方式存储。

可以很明显的看出存储方式对空间利用的优化。

其实实现的代码也很简单:

对小端模式的16bit读取重组(作者电脑C以大端模式读取数据),代码如下:

int tek_read(int i_offset, long long int offset, int readSum)
{
    FILE *odata = NULL;
    char *obuf = NULL;
    size_t bytes_read;
    //int16_t mid_data[DATA_BUF_SIZE];
    int16_t *mid_data;
    mid_data = (int16_t *)calloc((2 * readSum), sizeof(int16_t));
    int16_t temp = 0x00ff;
    int16_t temp1 = 0x0000;    //用来屏蔽污染中间变量,详情见下
    int i, j, l;
    int d, length = 0;
    int flag = 10;

    if (mid_data == NULL)
    {
        return FAILURE;
    }

    odata = fopen(DATA_name, "r+");
    if (odata == NULL)
    {
        free(mid_data);
        return FAILURE;
    }
    obuf = (char *)malloc((readSum * 2) * sizeof(char));    //动态分配内存 储存连续readSum *16b 数据
    if (obuf == NULL)
    {
        free(mid_data);
        free(obuf);
        return FAILURE;
    }
    long long int t_offset;
    t_offset = i_offset * offset * 2;
    flag = _fseeki64(odata, t_offset, 0);

    bytes_read = fread(obuf, 1, (2 * readSum), odata);

    fclose(odata);

    if (bytes_read < (2 * readSum + 1))
    {
        for (i = 0; i < (2 * readSum); i++)
        {
            mid_data[i] = obuf[i];
        }
        memset(Iri_data, 0, (2 * readSum));    //将Iri_data元素换成0
        for (j = 0; j < readSum; j++)
        {
            Iri_data[j] = mid_data[2 * j + 1];
            Iri_data[j] <<= 8;
            temp1 = mid_data[2 * j] & temp;    //某些低8位(类型是16位)的前8位读成ff导致或运算之后最终前8位成为ff,
            //为避免污染,先与0x00ff与运算
            Iri_data[j] |= temp1;
        }

        free(obuf);    //读到Iri_data中后就释放内存
        //数组长度
        d = 0;
        l = 0;
        //可能有连续5个0????末尾是0导致的问题
       free(mid_data);        //释放中间内部
        return length;
    }
    else
    {
        printf("* I am sorry to tell u there is a trouble                    
in taking Tektronix DATA!
Please cheak your settings!  
");

        free(mid_data);        //释放中间内存
        return 0;
    }
}
中间的信号处理就不详细介绍了
最后的大端模式将16bit有符号数据
写入文件,实现代码:
int outfile(void)
{

    FILE *fp_out;
    fp_out = fopen(outname, "a+");
    for (int i = 0; i < length_90ms_7Mhz; i++)
    {
        int16_t temp = Iridium_result_D16[i];
                //大端模式
        fputc((temp >> 8) & 0xFF, fp_out);
        fputc(temp & 0xFF, fp_out);
    }
    fclose(fp_out);

    return SUCCESS;
}

对于我200个G的原始数据,预处理效果很理想。

存储数据效果如下:

技术图片

 

 

以上是关于利用C一种最有效的文件存储方式——16bit有符号位2进制存储的主要内容,如果未能解决你的问题,请参考以下文章

Java -- 每日一问:Java有几种文件拷贝方式?哪一种最高效?

大小端存储

Java -- 每日一问:Java有几种文件拷贝方式?哪一种最高效?

将 char 数组转换为 uint16_t 数组 C/C++

float和double型分别怎么存储

浮点数存储方式