本次我们主要探讨一下如何在java中实现数据的大小端转换问题,那么我们就需要知道数据传输有哪几种形式。
针对16位传输,只存在正序(AB)或反序(BA)两种方式。
针对双字32位数据传输,存在四种顺序方式:
Big-endian :ABCD
Little-endian :DCBA
Big-endian byte swap :BADC
Little-endian byte swap :CDAB
其实java中的包装类给我们提供了很方便的转换成字节数组的方法,那么我们开始实现字节顺序的转换把。
一、如何获取字节形式。
要知道,在java中int和float都占4个字节,32位,因此我们可以只针对int类型进行处理,然后通过包装类型进行数据转换即可。借助下面方法即可把其他类型转为int或者long类型字节。
#float 转成int字节
float f = 17.61373519F;
int bigEndian = Float.floatToIntBits(f);
#double 转成long字节
double d = 123456.78964531;
long di = Double.doubleToLongBits(d);
二、创建字节顺序转换工具类
对于字节顺序操作效率最高的就是位运算了,这部分我们也可以在jdk源码中看到,jdk官方已经给我们提供了ABCD,DCBA两种顺序。
public class ByteOrderUtils{
/**
* Byte order is 'A B C D'
* @param num int number
* @return int number in big endian format
*/
public static int BigEndian(int num){
return num;
}
/**
* Byte order is 'D C B A'
* @param num int number
* @return int number in little endian format
*/
public static int LittleEndian(int num){
return Integer.reverseBytes(num);
}
/**
* Byte order is 'B A D C'
* @param num int number
* @return int number in big endian swap format
*/
public static int BigEndianWordSwap(int num){
return ((num&0xff00)>>>8)|
((num<<8)&0xff00)|
((num<<8)&0xff000000)|
((num &0xff000000)>>>8);
}
/**
* Byte order is 'C D A B'
* @param num int number
* @return int number in little endian swap format
*/
public static int LittleEndianWordSwap(int num){
return (num << 16)|(num >>> 16);
}
/**
* Byte order is 'A B C D E F G H'
* @param num long number
* @return long number in big endian format
*/
public static long BigEndian(long num){
return num;
}
/**
* Byte order is 'H G F E D C B A'
* @param num long number
* @return long number in little endian format
*/
public static long LittleEndian(long num){
return Long.reverseBytes(num);
}
/**
* Byte order is 'B A D C F E H G'
* @param num long number
* @return long number in big endian format
*/
public static long BigEndianWordSwap(long num){
return (num & 0x00ff00ff00ff00ffL) << 8 | (num >>> 8) & 0x00ff00ff00ff00ffL;
}
/**
* Byte order is 'G H E F C D A B'
* @param num long number
* @return long number in little endian format
*/
public static long LittleEndianWordSwap(long num){
return (num & 0xffff000000000000L) >>> 48 |
(num & 0x0000ffff00000000L) >>> 16 |
(num & 0x00000000ffff0000L) << 16 |
(num & 0x000000000000ffffL) << 48;
}
}
三、数据还原
使用包装类中的方法进行数据还原,如下例子。
public enum ByteOrder {
//A B C D
BIG_ENDIAN,
//D C B A
LITTLE_ENDIAN,
//B A D C
BIG_ENDIAN_WORD_SWAP,
//C D A B
LITTLE_ENDIAN_WORD_SWAP
}
public static void main(String[] args) {
float f = 17.61373519F;
int fi = Float.floatToIntBits(f);
double d = 123456.78964531;
long di = Double.doubleToLongBits(d);
System.out.println("A B C D:" + Float.intBitsToFloat(fi));
System.out.println("D C B A:" + Float.intBitsToFloat(ByteOrderUtils.LittleEndian(fi)));
System.out.println("B A D C:" + Float.intBitsToFloat(ByteOrderUtils.BigEndianWordSwap(fi)));
System.out.println("C D A B:" + Float.intBitsToFloat(ByteOrderUtils.LittleEndianWordSwap(fi)));
}
输出结果如下则,表示位运算正确。
A B C D:17.613735
D C B A:-3.598504E28
B A D C:-1.4940072E-31
C D A B:-9.001059E24