背景
项目中需要接收周期性(0.625ms)数据(128Bytes),并将数据保存、解析,之后需要将其以曲线的形式绘制出来。128字节数据需要解析出60项参数。
方案
原方案:
接收128字节数据后,先进行解析,将解析后的参数项以字符文本形式保存在.txt中,同时绘制实时参数曲线。在之后进行数据回放时,直接从文本文件中读取。
这种方法的优点是可以在文本中保存下各个参数的解析值,但是在回放绘制曲线时效率很低,耗时久。
改进方案:
接收128字节数据后,直接将此数据以二进制流的形式写入.bin文件,同时解析参数绘制实时曲线。在之后进行数据回放时,从.bin文件中读取、解算、绘图。
此方案的优点是保存文件小,读取时效率高,耗时少,占用内存可确定。
此处简单写了一段代码对两种方案的存取数据过程及读取耗时进行比较:
// binFileTry.cpp : 定义控制台应用程序的入口点。
// 2019-1-4 E705
#include "stdafx.h"
#include "iostream"
#include "iomanip"
#include "fstream"
#include "time.h"
#include "windows.h"
using namespace std;
ofstream outFileBin;
ofstream outFileTxt;
ifstream inFileTxt;
ifstream inFileBin;
int count_bin = 0;
int count_txt = 0;
int initialData(char * data)
{
for (int i = 0; i < 128; i++)
{
data[i] = rand()%100;
//std::cout << (int)data[i] << " ";
}
return 0;
}
int writeTxtFile(char * data)
{
for (int i = 0; i < 128; i += 4)
{
char pBuffer[20];
int tmp = ((data[i] << 24) & 0xff000000) + ((data[i + 1] << 16) & 0xff0000) + ((data[i + 2] << 8) & 0xff00) + data[i+3];
sprintf_s(pBuffer, sizeof(pBuffer), "%10d\t", tmp);
outFileTxt.write(pBuffer, strlen(pBuffer));
}
return 0;
}
int readTxtFile()
{
int buffer[32];
LARGE_INTEGER nFreq;
LARGE_INTEGER nBeginTime;
LARGE_INTEGER nEndTime;
QueryPerformanceFrequency(&nFreq);
QueryPerformanceCounter(&nBeginTime);
while (inFileTxt >> \
buffer[0] >> buffer[1] >> buffer[2] >> buffer[3] >> buffer[4] >> buffer[5] >> buffer[6] \
>> buffer[7] >> buffer[8] >> buffer[9] >> buffer[10] >> buffer[11] >> buffer[12] >> buffer[13] \
>> buffer[14] >> buffer[15] >> buffer[16] >> buffer[17] >> buffer[18] >> buffer[19] >> buffer[20] \
>> buffer[21] >> buffer[22] >> buffer[23] >> buffer[24] >> buffer[25] >> buffer[26] >> buffer[27] \
>> buffer[28] >> buffer[29] >> buffer[30] >> buffer[31])
{
count_txt++;
//显示以查看读取是否正确
// for (int i = 0; i < 32; i++)
// {
// cout << setw(16) << buffer[i] << " ";
// }
// cout << endl;
}
QueryPerformanceCounter(&nEndTime);
double time = (double)(nEndTime.QuadPart - nBeginTime.QuadPart) / double(nFreq.QuadPart) * 1000;
cout << time << "\n";
return 0;
}
int readBinFile_oneLine()
{
char buffer[128];
LARGE_INTEGER nFreq;
LARGE_INTEGER nBeginTime;
LARGE_INTEGER nEndTime;
QueryPerformanceFrequency(&nFreq);
QueryPerformanceCounter(&nBeginTime);
while (!inFileBin.eof() && inFileBin.peek() != EOF)
{
inFileBin.read(buffer, sizeof(char)* 128);
for (int i = 0; i < 128; i += 4)
{
int tmp = ((buffer[i] << 24) & 0xff000000) + ((buffer[i + 1] << 16) & 0xff0000) + ((buffer[i + 2] << 8) & 0xff00) + buffer[i + 3];
count_bin++;
cout << setw(16) << tmp << " ";
}
cout << endl;
}
QueryPerformanceCounter(&nEndTime);
double time = (double)(nEndTime.QuadPart - nBeginTime.QuadPart) / double(nFreq.QuadPart) * 1000;
cout << time << "\n";
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
//将采集(生成)的数据写入文件
outFileBin.open("..\\..\\1.bin", ios::binary);
outFileTxt.open("..\\..\\1.txt", ios::out);
char binData[128];
char nextLine[2] = { 0x0a, 0X0D };
srand((unsigned int)time(NULL));
int totalTime = 5*60*1000 / 0.625; //生成5min中数据
for (int i = 0; i < totalTime; i++)
{
initialData(binData);
//std::cout << "\n";
writeTxtFile(binData);
outFileTxt.write("\r\n", 2);
outFileBin.write(binData, 128);
}
outFileBin.close();
outFileTxt.close();
//从文件中读取数据,并比较操作时间
inFileBin.open("..\\..\\1.bin", ios::binary);
inFileTxt.open("..\\..\\1.txt", ios::in);
readTxtFile(); //原方案花费时间:66543.7ms 65594.1ms 66566.3ms
readBinFile_oneLine(); //使用二进制花费时间:517.953ms 478.404ms 456.393ms
cout << endl << count_bin;
cout << endl << count_txt*32;
inFileBin.close();
inFileTxt.close();
return 0;
}
耗时结果比较:
实验次数 | 1 | 2 | 3 |
---|---|---|---|
原方案耗时/ms | 66543.7 | 65594.1 | 66566.3 |
改进方案耗时/ms | 517.953 | 478.404 | 56.393 |
表格创建参考:利用Markdown创建表格