前言
大学毕业后来到公司的第一件工作就是通过U盘插入装有安卓系统的机器,通过U盘向机器设置设备码(下称SN)。一开始我的思路就是通过InStream先取到U盘里文件的数据,然后通过OutStream修改文件,然后把读出来的SN通过封装好的api接口发到机器上就完事。思路大体是对的,但是中间过程折磨了我这个新手好几天,接下来我将对其中的每一个环节进行分析。
一、十六进制dat文件解析
如果大家也有做到关于读取字节文件dat的,一定一定一定要问你的负责人要到关于dat文件的格式说明!!!不然会超级麻烦。话不多说,先展示一下我的dat文件的格式:
上述图片就是我用到的sn.dat文件。这里就不提我的摸索痛苦经历了,直接上结论。
首先最左边一列(“空格”前那一串数字)并不是我们会读取到的数据,我的理解是一种序号并且在你读写文件的时候并不会影响到,相当于是隐形的,简单来说就是可以不用管,这东西给你是方便看的。当然空格也是,实际上并没有空格,都是用来方便看的。然后最右边呢一串像乱码一样的东西也不用管,我的负责人跟我说是类似注解说明一样的东西,所以这个dat文件实际对我们有用的部分就是中间这一大块数据。
我这个dat文件是十六进制的形式,我们把每一行分为4组,每一组8个数。拿一行的第一组为例:803E0000 我先说结论,每两个数表示一个十六进制数,每4个十六进制数也就是一组代表一个数,我这里的数据采用的是小端结构,所以读出来就是"0x00、0x00、0x3E、0x80",换成十进制就是16000。解释一下,一个int型数据有4个字节,4byte就是32位,一个十六进制的数据(0x3E 这样)是8位,所以4个十六进制数就代表了一个int型的数。然后关于什么是小端结构,小端结构说白了就是低位写在前面,我们平时写的数据就是相反的大端结构,是高位写在前面。在硬件底层一般数据传输用的都是小端结构,通讯协议用的是大端结构。具体的详解可以百度大端、小端模式。
二、十六进制dat文件读操作
在读dat文件之前,我先说明一下我的文件格式,前4个字节存的是读到第几个SN号,9-12个字节存放的是SN号总数。然后从第六行开始,每8个字节为一组,前4个字节是标志位,0代表SN没用过,1代表已使用过;后4个字节才表示SN号。
1.读取手机中的dat文件数据
这里与一般读写文件的区别在于我们是需要读写字节文件,代码如下。
public static void changeDat(File file) {
FileInputStream inStream = null;
FileOutputStream outStream = null;
SNFileStream snFileStream = new SNFileStream();
int dataPos = 0;//SN码到的使用位置
int dataCount = 0;//SN码总数
byte[] bytes = new byte[220 * 1024];//获取sn.dat内容
int SNFlag = 0;//标志位
int SNValue = 0;//设备号
String StrSNValue = "";
File newFile = new File("/mnt/shared/Pictures/sn2.dat");
try {
inStream = new FileInputStream(file);
outStream = new FileOutputStream(newFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
//getChannel()该方法的返回类型为FileChannel,它返回与此流连接的FileChannel。
ReadableByteChannel inCh = inStream.getChannel();
{
//分配直接字符缓冲区
ByteBuffer buffer = ByteBuffer.allocateDirect(16);
//ByteOrder.LITTLE_ENDIAN表示小端模式
buffer.order(ByteOrder.LITTLE_ENDIAN);
int num = 0;
while (true) {
try {
if (inCh.read(buffer) == -1) break;
} catch (IOException e) {
e.printStackTrace();
}
buffer.flip();
bytes[num] = buffer.get();
num++;
buffer.compact();
}
//关闭FileInPutStream
try {
inStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
2.修改dat文件
把dat文件里的内容全部读出来存入byte数组后,拿出需要的数据并将需要修改的内容在byte数组中改,然后重新存入一个dat文件替代原来的文件,代码如下(接上)。
//获取索引 4个byte代表一个32位的十六进制数
byte[] mid = new byte[4]; //取32位十六进制数
for (int i = 0; i < 4; i++) {
mid[i] = bytes[i];
}
dataPos = snFileStream.byte2int(mid);
Log.d("dataPos", String.valueOf(dataPos));
//更新dataPos
int updateDataPos = dataPos + 2;
mid = snFileStream.int2byte(updateDataPos);
for (int i = 0; i < 4; i++) {
bytes[i] = mid[i];
}
//获取总数
for (int i = 0; i < 4; i++) {
mid[i] = bytes[i + 8];
}
dataCount = snFileStream.byte2int(mid);
Log.d("dataCount", String.valueOf(dataCount));
//获取SN码
int SNValuePos = 4 + 8 * (dataPos - 1) + 80;