Java大小端与报文解析

定义

要想搞懂大小端,首先得明白大小端的定义,以下是百度的定义

下面以unsigned int value = 0x12345678为例,分别看看在两种字节序下其存储情况,我们可以用unsigned char buf[4]来表示value

Big-Endian: 低地址存放高位,如下:

1
2
3
4
5
6
高地址
buf[3] (0x78) -- 低位
buf[2] (0x56)
buf[1] (0x34)
buf[0] (0x12) -- 高位
低地址

Little-Endian: 低地址存放低位,如下:

1
2
3
4
buf[3] (0x12) -- 高位
buf[2] (0x34)
buf[1] (0x56)
buf[0] (0x78) -- 低位

所谓的大端模式(Big-endian),是指数据的高字节,保存在内存的低地址中,而数据的低字节,保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;

所谓的小端模式(Little-endian),是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。

工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/**
* 字节数组转int
* 大端模式
* @param b
* @return
*/
public static int byteArray2BigInt(byte[] b) {
int intValue = 0;
for (int i = 0; i < b.length; i++) {
intValue += (b[i] & 0xFF) << (8 * (3 - i));
}
return intValue;
}



/**
* 字节数组转int
* 小端模式
* @param b
* @return
*/
public static int byteArray2LittleInt(byte[] b){
int initValue = 0;
for (int i = 0; i < b.length; i++){
initValue += (b[i] & 0xFF) << (8 * i);
}
return initValue;
}


/**
* 大端模式
* @param iValue
* @return
*/
public static byte[] int2ByteArrayBig(int iValue){
byte[] b = new byte[4];
for (int i = 0; i < b.length; i++){
b[3-i] = (byte)((iValue >> (8 * i)) & 0xFF);
}
return b;
}

/**
*小端模式
* @param iValue
* @return
*/
public static byte[] int2ByteArrayLittle(int iValue){
byte[] b = new byte[4];
for (int i = 0; i < b.length; i++){
b[i] = (byte)((iValue >> (8 * i)) & 0xFF);
}
return b;
}

断点调试

1
2
3
4
5
6
7
int a = 257;

byte[] bytes = ParseUtils.int2ByteArrayBig(a);
byte[] bytes1 = ParseUtils.int2ByteArrayLittle(a);

int i = ParseUtils.byteArray2BigInt(bytes);
int i1 = ParseUtils.byteArray2LittleInt(bytes1);

工业报文

Java由于int 4个字节。很多工业数据都是16进制报文,用1个字节或者2个字节表示int。所以做此记录.

先上个工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.ud.ruleengine.utils;

import java.math.BigInteger;

public class ParseUtils {

/**
* 截取byte数组
* @param src
* @param begin
* @param count
* @return
* 小端,有符号
*/
public static byte[] subBytes(byte[] src, int begin, int count) {
byte[] bs = new byte[count];
System.arraycopy(src, begin, bs, 0, count);
return bs;
}



/**
* 字节数组转不同进制字符串
* @param bytes
* @param radix
* @return
*/
public static String binary(byte[] bytes, int radix){
return new BigInteger(1, bytes).toString(radix);// 这里的1代表正数
}
}

base64解析工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.ud.ruleengine.utils;

import java.io.IOException;
import java.util.Base64;

public class Base64Encrypt {

static Base64.Decoder decoder = Base64.getDecoder();
static Base64.Encoder encoder = Base64.getEncoder();

/**
* 编码
*
* @param bstr
* @return String
*/
public static String encode(byte[] bstr) {
return encoder.encodeToString(bstr);
}
/**
* 解码
*
* @param str
* @return string
*/
public static byte[] decode(String str) {
byte[] bt = null;
try {
bt = decoder.decode(str);
} catch (Exception e) {
e.printStackTrace();
}

return bt;
}
}

假设6个字段分别是212212个字节,int值,那么我们的解析为:

1
2
3
4
5
6
7
8
byte[] decode = Base64Encrypt.decode(data);

String a1 = ParseUtils.binary(ParseUtils.subBytes(decode, 0, 2), 10);
String a2 = ParseUtils.binary(ParseUtils.subBytes(decode,2,1), 10);
String a3 = ParseUtils.binary(ParseUtils.subBytes(decode,3,2), 10);
String a4 = ParseUtils.binary(ParseUtils.subBytes(decode,5,2), 10);
String a5 = ParseUtils.binary(ParseUtils.subBytes(decode,7,1), 10);
String a6 = ParseUtils.binary(ParseUtils.subBytes(decode,8,2), 10);