C++ 读写二进制文件

描述

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);

代码解释

  1. 首先要知道你要读取的二进制文件,其存放的格式是什么
  2. 根据存放的数据格式,你来定义该数据格式的变量
    例如,你的数据存放了一个uint8_t格式的id1和一个uint16_t格式的id2
    那么你就应该定义这样的变量
  3. 再通过以上代码中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

猜你喜欢

转载自blog.csdn.net/weixin_42156097/article/details/128788343