在解析一些数据库或文件中,有些内容会用一些有规定的规则进行存储,如mmkv,这种时候如果需要提取内容只能对其进行拆分,而一般都是用二进制流的读取方式读取规律解析
这是自己写的一个二进制流数据读取类
二进制流数据读取类
这边是一个qq消息的内容文件
可以看到消息内容是根据一定方式存储的,粗略来看前8个字节为标志,表示为是一个MSG消息,后8位不明
然后消息内容的存储都是以TD(54 44 01 01)来进行标记
那么可以进行如下解析
简单作个图
即可以这样
#include"ByteRead.h"
#include<iostream>
#include<fstream>
#include <memory>
#include<vector>
bool CheckLen(int at, int len)
{
if (at > len || at < 0)
return false;
return true;
}
int main()
{
std::ifstream file;
file.open("MsgContent1", std::ios::in||std::ios::binary);
if (file.fail())
{
return 0;
}
file.seekg(0, file.end);
int length = file.tellg();
std::cout << "文件大小为:" << length << std::endl;
file.seekg(0, file.beg);
auto buffer = std::make_shared<char>(length);
file.read(buffer.get(), length);
file.close();
ByteReader byte_read((unsigned char*)buffer.get(), length);
unsigned int head = byte_read.GetUInt32(); //获取4位标识
if (Head != 0x0047534d) //Msg
{
return 0;
}
byte_read.Skip(8);
unsigned char pPath[4] = { 0x54,0x44,0x01,0x01 };
int at = byte_read.FindChar(pPath, 4, byte_read.offset_); //找到TD这个标志
if (at < 0)
{
return 0;
}
int next = byte_read.FindChar(pPath, 4, at + 4);//再找下一个TD
int64_t space;
if (next < 0) //因为规律并不明确,我们需要防止在读取时过界导致程序出错,所以计算出每个TD之间的长度,如果在解析一段时超出则退出或进行标记,来看是什么情况
space = byte_read.len_ - at;
else
space = next - at;
byte_read.Skip(at - byte_read.offset_); //将byte_read的下标移动到读取的地方,即第一个TD的地方
byte_read.Skip(6);//再往后6位
int ntype = byte_read.GetByte(); //读取1位为表示这个内容的类型,GetByte()自动移了1位
int nLen = byte_read.GetUInt16(); //读取两位为这个内容key的长度
if (!CheckLen(nLen, space - (byte_read.offset_ - at))) //保证不超过两个TD的距离
return 0;
byte_read.Skip(2); //移动2位
std::string strUnknow = byte_read.GetString(byte_read.offset_, nLen);//根据长度获取key
byte_read.Skip(nLen);
nLen = byte_read.GetUInt32();
if (!CheckLen(nLen, space - (byte_read.offset_ - at)))
return 0;
byte_read.Skip(4);
std::string strUnknow1 = byte_read.GetString(byte_read.offset_, nLen);//根据长度获取value,即数据存储方式为KEY-VALUE,key和value进行了加密,需要解密才能知道正确内容
}
因为解析复杂,这里只给出了取一段的方式,可以根据上面给出的例子发现第一个TD的value其实是一个嵌套了TD的(长度为99 00 00 00),需要再次处理。