描述
C++来读取二进制文件
二进制文件的格式可以多种多样,比如dat、index等,还可以是自行定义的格式
C++来写二进制文件
一、读二进制文件
结构体定义及头文件
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
struct index_data {
uint16_t id1;
uint8_t id2;
};
index_data my_index;
打开二进制文件
FILE * fp;
if((fp=fopen("../1.dat","rb"))==NULL) //rb代表按照二进制的方式进行读
{
printf("cant open the file");
exit(0);
}
读取二进制文件
while(fread(&my_index, sizeof(index_data), 1, fp) == 1) //如果读到数据,就显示;否则退出
{
std::cout<<std::hex<<int(my_index.id)<<std::endl; // 十六进制显示
std::cout<<std::dec<<int(my_index.id)<<std::endl; // 十进制显示
}
使读取指针跳到指定位置
比如,跳100个字节
fseek(fp, 100, 0);
关闭文件
注意,每一次再fopen同一文件前,一定要先fclose一下
fclose(fp);
代码解释
- 首先要知道你要读取的二进制文件,其存放的格式是什么
- 根据存放的数据格式,你来定义该数据格式的变量
例如,你的数据存放了一个uint8_t格式的id1和一个uint16_t格式的id2
那么你就应该定义这样的变量 - 再通过以上代码中while的语句,从二进制文件中,持续读出你想要的数据
几个重要细节
数据占位
std::cout<<"int: "<<sizeof(int)<<std::endl;
std::cout<<"char: "<<sizeof(char)<<std::endl;
std::cout<<"float: "<<sizeof(float)<<std::endl;
std::cout<<"double: "<<sizeof(double)<<std::endl;
std::cout<<"uint8_t: "<<sizeof(uint8_t)<<std::endl;
std::cout<<"uint16_t: "<<sizeof(uint16_t)<<std::endl;
std::cout<<"uint32_t: "<<sizeof(uint32_t)<<std::endl;
int: 4
char: 1
float: 4
double: 8
uint8_t: 1
uint16_t: 2
uint32_t: 4
几种常见数据所占的字节数
数据对齐
#pragma pack(1)
在这句代码后面的数据定义,会按照1个字节来对齐数据
举例子
-
如果不加
#pragma pack(1)
这句话,代码会自动对齐字节struct data{ char a; int n; }; std::cout<<sizeof(data)<<std::endl;
你会得到输出结果为8,因为char为1,int为4,而data的数据占位在char型变量a后面会留3个空字节,char1个字节+3个空字节+int4个空字节=8个字节
-
而加上
#pragma pack(1)
,你会发现输出结果为5
因为你预定义了,数据按1字节来对齐 -
因此同样的数据格式,data1的size为8个字节,而data2的size为5个字节
struct data1{ char a; int n; }; #pragma pack(1) struct data2{ char a; int n; };
uint16_t的读取问题
uint16_t占2个字节,因此它存在数据高位和低位
uint16_t id = 0x3FC6;
uint8_t low = id & 0xFF;
uint8_t high = (id >> 8) & 0xFF;
std::cout<<std::hex<<int(high)<<" "<<int(low)<<std::endl;
// 输出结果:3f c6
std::cout<<std::hex<<int(high)<<" "<<int(low)<<std::endl;
// 输出结果:63 198
std::cout<<std::dec<<a<<std::endl;
// 输出结果:16326
解释一下
3f、 c6:原本的数据高位和数据低位
63 、198: 3f、 c6由十六进制转成十进制
16326:id的值3FC6,由十六进制转成十进制的结果
如果输出代码中不加int(),high的输出会是“?”
因为63在二进制中代表了“?”
uint8_t xxx = 43;
std::cout<<xxx<<std::endl; // 输出结果为43代表的“+”
二、写二进制文件
头文件
#include <iostream>
#include <fstream>
假设我们有结构体需要写
struct A {
int a,
int b;
};
struct B {
std::string x,
std::string y;
};
调用
std::string filename = "../1.dat" ;
std::ofstream fout;
fout.open(filename, std::ios::out| std::ios::app | std::ios::binary);
if (fout.is_open() == false)
{
std::cout << "打开文件" << filename << "失败。"<<std::endl;
return 0;
}
A data_1;
B data_2;
fout.write((const char*)&data_1, sizeof(A));
fout.write((const char*)&data_2, sizeof(B));
std::cout<<"sizeof(A):"<<sizeof(A)
<<" sizeof(B):"<<sizeof(B)<<std::endl;
fout.close();
命令
在终端查看二进制dat文件
hexdump 1.dat
比较两个二进制文件是否相同
cmp 1.dat 2.dat