Qt开发二进制文件读取与操作学习汇总

Qt开发二进制文件读取与操作学习汇总

  • 导言
    • Qt API:QFile and QDataStream
      • write
      • Read
    • C原生API:FILE(fopen,fread,fseek,fwrite)
        • 分析;
        • 逐字节以规定字节数写入:
    • C++API:ofstream
        • Write;
    • Windons API:CreateFileA,GetFileSize,ReadFile
        • 分析:
        • 其他
    • 注意

导言

最近在进行Qt开发,涉及大量的matlab转C的工作,其中有很大一部分工作是读取二进制文件并对数据进行操作,而在matlab里简易清晰的读取方式,用C来实现往往会遇到很多问题,因此工作告一段落之后对近期学习工作的成果做总结以备不时之需也是必要的。

fseek(fid,0,'eof');           %指针移到文件数据末尾
Blen=ftell(fid);              %获得指针位置  即末尾的位置,相当于数据长度
fseek(fid,0,'bof');           %重新回到文件数据开头

//uint8一个字节,uint16两个字节,uint32四个字节
obj_num=fread(fid,1,'uint8'); %读取第一个字节的数据并转为十进制给obj_num
rat=fread(fid,1,'uint8');   	%接着读取文件第二个字节的数据转为十进制给rat
fread(fid,1,'uint16');        	%接着第3,4字节的数据,但并不赋值
L=fread(fid,1,'uint16');   	   %接着读取第5.6字节的数据,转为十进制给L

ys_da=fread(fid,L,'int16'); 	% 接着读取L个int16的数据每个都转为十进制,以数组的方式保存在ys_da里

Qt API:QFile and QDataStream

write

qt自带API会将多字节数据反序存储,因此我们读取之后,写入之前,需要把数据反序操作
   template <typename T>
   T ReverseOrder(T oldValue)
   {
   	T newValue;
   	int size = sizeof(T);
   	memset(&newValue, 0, size);
   	for (int i = 0; i < size; i++) {
   		//挨个取字节
   		BYTE value = (oldValue >> (i * 8)) & 0xFF;
   		memset((char*)&newValue + size - i - 1, value, 1);
   	}
   	return newValue;
   }
   QFile file(Wpath);
   file.open(QIODevice::WriteOnly);
   QDataStream out(&file);
   
   out << qint8(1);
   out << qint8(1);
   out << ReverseOrder(qint32(23.5));
   out << qint32(0);
   out << qint32(0);
   out << qint8(1);
   file.flush();
    QVector<int> Id3(LEN), Qd3(LEN);
   	//输出滤波后的数据
   	for (int j = 0; j < LEN; j++) {
   		Id3[j] = mathfunc.fix(temp1_iq.real[j + lbn]);
   		Qd3[j] = mathfunc.fix(temp1_iq.imag[j + lbn]);
   		out << ReverseOrder(qint16(Id3[j]));
   		out << ReverseOrder(qint16(Qd3[j]));
   	}
   	file.flush();
   	file.close();

Read

   	QFile file(Rpath);
   	if (!file.open(QFile::ReadOnly))
   	{
   		qDebug() << "Could not open file for reading";
   		return;
   	}
   	qint8 obj_num;
   	qint8 rat;
   	qint16 dd;
   	qint16 L;
   	QDataStream MyRead(&file);
   	MyRead >> obj_num;
   	MyRead >> rat;
   	MyRead >> dd;
   	MyRead >> L;
   	qDebug() << ReverseOrder(obj_num) << ReverseOrder(rat)  << ReverseOrder(dd) << ReverseOrder(L);

C原生API:FILE(fopen,fread,fseek,fwrite)

分析;

完美符合需求,也是matlab的读二进制文件的实际方法,只不过matlab应该是对原来的api进行了重载,功能大差不错
   //QString  类型转换 const char *
   	QByteArray ba1;
   	ba1.append(Rpath);
   	const char *rpath = ba1.data();

   	FILE * rfid = fopen(rpath, "rb");
   	if (rfid == NULL)
   	{
   		QString theLog = "没有成功打开" + filename + "文件";
   		QMessageBox::warning(this, "警告!", theLog);
   		return;
   	}
   	fseek(rfid, 0, 2);
   	int Blen = ftell(rfid);
   	fseek(rfid, 0, 0);

   	UINT8 obj_num;	
   	UINT8 rat;
   	UINT16 dd;	
   	UINT16 L;
   	//fread(存放地址,单个数据的字节数,读几个数据,文件柄)   返回值为0或1
   	fread(&obj_num, sizeof(UINT8), 1, rfid);
   	fread(&rat, sizeof(UINT8), 1, rfid);
   	fread(&dd, sizeof(UINT16), 1, rfid);
   	fread(&L, sizeof(UINT16), 1, rfid);
   	printf("%d\n ", obj_num);
   	printf("%d\n ", rat);
   	printf("%d\n ", dd);
   	printf("%d\n ", L);

逐字节以规定字节数写入:

   //解决中文路径乱码
   //Wpath是你的文件路径
   QTextCodec *code = QTextCodec::codecForName("GB2312");
   std::string name = code->fromUnicode(Wpath).data();
   FILE * wfid = fopen(name.c_str(), "wb");
   //单个数据
   int buf = 1;
   int buf1 = 1000000;
   int buf2 = 0;
   fwrite(&buf, 1, 1, wfid);  //01
   fwrite(&buf, 1, 1, wfid);  //01
   fwrite(&buf1, 4, 1, wfid); //40 42 0F 00
   fwrite(&buf2, 4, 1, wfid); //00 00 00 00
   fwrite(&buf2, 4, 1, wfid); //00 00 00 00
   fwrite(&buf, 1, 1, wfid);  //01

   //一个数组  data是你的数据,LEN是你的数组长度
   	INT16 *outD = new INT16[LEN];
   	//输出滤波后的数据
   	for (int j = 0; j < LEN; j++) {
   		outD[j] = data[j];
   	}
   	//写文件
   	fwrite(outD, sizeof(INT16), LEN, wfid);
   	//清理内存空间
   	delete outD;

C++API:ofstream

Write;

   std::ofstream ofs(name.c_str(), std::ios::out | std::ios::binary);	//创建输出流对象
   int buf = 1;
   int buf1 = mathfunc.fix(FSO);
   int buf2 = 0;
   
   ofs.write((const char*)&buf, sizeof(buf));//写文件
   ofs.write((const char*)&buf, sizeof(buf));//写文件
   ofs.write((const char*)&buf1, sizeof(buf1));//写文件
   ofs.write((const char*)&buf2, sizeof(buf2));//写文件
   ofs.write((const char*)&buf2, sizeof(buf2));//写文件
   ofs.write((const char*)&buf, sizeof(buf));//写文件
   ofs.flush();
   ofs.close();

Windons API:CreateFileA,GetFileSize,ReadFile

分析:

1.完美满足需求
2.思路:先将数据全部读进来,再以指针寻址的方式将对应的数据以对应字节数取出,方便易用
char* Vsqt::MyOpenFile(QString path)
{
   char* fileBuff;
   // 解决中文路径
   QTextCodec *code = QTextCodec::codecForName("GB2312");
   std::string name = code->fromUnicode(path).data();
   HANDLE hFile = ::CreateFileA(name.c_str(),
   	GENERIC_READ,
   	0,
   	NULL,
   	OPEN_EXISTING,
   	FILE_ATTRIBUTE_NORMAL, NULL
   );

   fileSize = ::GetFileSize(hFile, 0);
   fileBuff = new char[fileSize];
   DWORD realRead;

   bool bsucess = 0;
   bsucess = ::ReadFile(hFile, fileBuff, fileSize, &realRead, NULL);
   if (!bsucess)
   	return 0;
   CloseHandle(hFile);

   return fileBuff;
}
   	char *fileBuff = MyOpenFile(Rpath);			//读取全部数据
   	if (fileBuff == 0)
   	{
   		QString theLog = "没有成功打开" + filename + "文件";
   		QMessageBox::warning(this, "Warning!", theLog);
   		return;
   	}
   	
   	int obj_num = *(BYTE*)fileBuff;		
   	int rat = *(BYTE*)(fileBuff + 1);	
   	int dd = *(WORD*)(fileBuff + 2);	
   	int L = *(WORD*)(fileBuff + 4);	
   	int Blen = fileSize;
   	cout << obj_num << endl << rat << endl << dd << endl << L << endl;

其他

注意:当我们的数据不知道是正数还是负数时且字节数不够表达这个数时我们需要像如下的操作:

	vector<double> ys_da;					//  里面为要计算的数据,一个数据为2个字节
   //处理计算数据,判断正负进行
   	for (int i = 0; i < wlen; i++) {
   		if ((*(WORD*)fileBuff & 0x8000) == 0)	//正数
   			ys_da.push_back(*(WORD*)fileBuff);
   		else {									//负数
   			ys_da.push_back((INT32)(*(WORD*)fileBuff | 0xFFFF0000));
   		}
   		fileBuff = fileBuff + 2;
   	}

注意

该文章仅个人学习使用,欢迎大家一起交流学习

你可能感兴趣的:(C,二进制文件读取,逐字节读取二进制数据,matlab转C,c++,c语言,windows,visual,studio)