new IO学习笔记(二)之字节存放顺序

细谈字节存放顺序问题:

字节序,又称端序,尾序,英文:Endianness。在计算机科学领域中,字节序是指存放多字节数据的字节(byte)的顺序,典型的情况是整数在内存中的存放方式和网络传输的传输顺序。Endianness有时候也可以用指位序(bit)。

一般而言,字节序指示了一个UCS-2字符的哪个字节存储在低地址。如果LSByteMSByte的前面,即LSB为低地址,则该字节序是小端序;反之则是大端序。在网络编程中,字节序是一个必须被考虑的因素,因为不同的处理器体系可能采用不同的字节序。在多平台的代码编程中,字节序可能会导致难以察觉的bug

处理器体系:

网络序

网络传输一般采用大端序,也被称之为网络字节序,或网络序IP协议中定义大端序为网络字节序。

伯克利socket API定义了一组转换函数,用于16和32bit整数在网络序和本机字节序之间的转换。htonl,htons用于本机序转换到网络序;ntohl,ntohs用于网络序转换到本机序。


--------------------------------------------------------------------------------------------------------------------------------------------------

代码段一:

ByteBuffer buf = ByteBuffer.wrap(new byte[10]);

buf.asCharBuffer().put("abcde");
System.out.println(Arrays.toString(buf.array()));
System.out.println("----------------------------------------------");

buf.rewind();
buf.order(ByteOrder.BIG_ENDIAN);
buf.asCharBuffer().put("abcde");
System.out.println(Arrays.toString(buf.array()));
System.out.println("----------------------------------------------");


buf.rewind();
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.asCharBuffer().put("abcde");
System.out.println(Arrays.toString(buf.array()));

打印结果:

[0, 97, 0, 98, 0, 99, 0, 100, 0, 101]
----------------------------------------------
[0, 97, 0, 98, 0, 99, 0, 100, 0, 101]
----------------------------------------------
[97, 0, 98, 0, 99, 0, 100, 0, 101, 0]

*************************************************************************************************************************

代码段二:

ByteBuffer buf = ByteBuffer.wrap(new byte[10]);
buf.asCharBuffer().put("abcde");
System.out.println(Arrays.toString(buf.array()));
System.out.println("----------------------------------------------");

buf.rewind();
buf.order(ByteOrder.BIG_ENDIAN);
buf.asCharBuffer().put("abcde");
System.out.println(Arrays.toString(buf.array()));
System.out.println("----------------------------------------------");


buf.rewind();
buf.order(ByteOrder.LITTLE_ENDIAN);
//buf.asCharBuffer().put("abcde");
System.out.println(Arrays.toString(buf.array()));

打印结果:

[0, 97, 0, 98, 0, 99, 0, 100, 0, 101]
----------------------------------------------
[0, 97, 0, 98, 0, 99, 0, 100, 0, 101]
----------------------------------------------
[0, 97, 0, 98, 0, 99, 0, 100, 0, 101]

***********************************************************************************************************************

代码段三:

ByteBuffer buf = ByteBuffer.wrap(new byte[10]);
buf.asCharBuffer().put("abcde");
System.out.println(Arrays.toString(buf.array()));
System.out.println("----------------------------------------------");

buf.rewind();
buf.order(ByteOrder.BIG_ENDIAN);
buf.asCharBuffer().put("abcde");
System.out.println(Arrays.toString(buf.array()));
System.out.println("----------------------------------------------");


buf.rewind();
buf.asCharBuffer().put("abcde");
buf.order(ByteOrder.LITTLE_ENDIAN);

System.out.println(Arrays.toString(buf.array()));

打印结果:

[0, 97, 0, 98, 0, 99, 0, 100, 0, 101]
----------------------------------------------
[0, 97, 0, 98, 0, 99, 0, 100, 0, 101]
----------------------------------------------
[0, 97, 0, 98, 0, 99, 0, 100, 0, 101]

综合以上调试结果分析得知:

ByteBufferorder(ByteOrderbo)修改此缓冲区的字节顺序。

当我们调用这一方法时,必须首先用order(ByteOrderbo)方法设置字节的排放次序,然后再向缓冲中存入相应的值,这个时候才能得到我们想要的结果(字节的存放顺序是根据CPU的不同而不同)。

代码段四:

public static void long2Byte(long num) {
ByteBuffer buf = ByteBuffer.wrap(new byte[8]);
buf.asLongBuffer().put(num);
System.out.println("默认的字节存放顺序:"+Arrays.toString(buf.array()) +"\n当前字节存放方式:"+buf.order());
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.asLongBuffer().put(num);

System.out.println("改后的字节存放顺序:"+Arrays.toString(buf.array()) +"\n改后字节存放方式:"+buf.order());

}

打印结果:传入参数为:8L

默认的字节存放顺序:[0, 0, 0, 0, 0, 0, 0, 126]
当前字节存放方式:BIG_ENDIAN
改后的字节存放顺序:[126, 0, 0, 0, 0, 0, 0, 0]
改后字节存放方式:LITTLE_ENDIAN

******************************************************************************************************************************

代码段五:

public static void long2Byte(long num) {
ByteBuffer buf = ByteBuffer.wrap(new byte[8]);
buf.asLongBuffer().put(num);
System.out.println("默认的字节存放顺序:"+Arrays.toString(buf.array()) +"\n当前字节存放方式:"+buf.order());

buf.asLongBuffer().put(num);
buf.order(ByteOrder.LITTLE_ENDIAN);
System.out.println("改后的字节存放顺序:"+Arrays.toString(buf.array()) +"\n改后字节存放方式:"+buf.order());

}

打印结果:传入参数为:8L

默认的字节存放顺序:[0, 0, 0, 0, 0, 0, 0, 126]
当前字节存放方式:BIG_ENDIAN
改后的字节存放顺序:[0, 0, 0, 0, 0, 0, 0, 126]
改后字节存放方式:LITTLE_ENDIAN

代码段六:

/*
* long 与byte[]之间的转换
*/
public static byte[] long2Byte(long num) {
ByteBuffer buf = ByteBuffer.wrap(new byte[8]);
buf.asLongBuffer().put(num);
System.out.println("默认的字节存放顺序:"+Arrays.toString(buf.array()) +"\n当前字节存放方式:"+buf.order());
buf.rewind();
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.asLongBuffer().put(num);
System.out.println("改后的字节存放顺序:"+Arrays.toString(buf.array()) +"\n改后字节存放方式:"+buf.order());
byte[] array = Arrays.copyOfRange(buf.array(), 0, 2);//将当前8字节数组截取位2个字节长度
return array;

}


public static long byte2Long(byte[] b) {
byte[] copyOf = Arrays.copyOf(b, 8); //将2个字节长度的数组还原成8个长度的数组
ByteBuffer buf = ByteBuffer.wrap(copyOf);
System.out.println("默认的字节存放顺序:"+Arrays.toString(buf.array()) +"\n当前字节存放方式:"+buf.order());
buf.order(ByteOrder.LITTLE_ENDIAN);
System.out.println("改后的字节存放顺序:"+Arrays.toString(buf.array()) +"\n改后字节存放方式:"+buf.order());
return buf.asLongBuffer().get();
}

测试:

public static void main(String[] args) {
byte[] b = ConvertUtils.long2Byte(126);
System.out.println(Arrays.toString(b));
long l = ConvertUtils.byte2Long(b);
System.out.println(l);
}

打印结果:

默认的字节存放顺序:[0, 0, 0, 0, 0, 0, 0, 126]
当前字节存放方式:BIG_ENDIAN
改后的字节存放顺序:[126, 0, 0, 0, 0, 0, 0, 0]
改后字节存放方式:LITTLE_ENDIAN
[126, 0]
默认的字节存放顺序:[126, 0, 0, 0, 0, 0, 0, 0]
当前字节存放方式:BIG_ENDIAN
改后的字节存放顺序:[126, 0, 0, 0, 0, 0, 0, 0]
改后字节存放方式:LITTLE_ENDIAN
126

以上测试表明:

1.我们对一个小于2个字节长度的long型数字传入,再通过byte2Long()方法返回出刚才输入的数字,这种方式较常用于对于网络信息的编码解码。

如果不明白为什么传入的是2个字节长度的long型数字,那么就可以将红色部分代码注释掉,将蓝色的copyOf换成传入的字节数组b,那么上述代码就是对一个long型数字的高位和地位存放顺序的调换的工具类。因本人当前为高位存储,所以将其转成了低位存放方式。最后再将其转换为高位得到原始输入的数据。

2.我们关注一下绿色的打印内容,会发现我们明明已经对输入的字节数组进行了低位转换,可是输出时发现没有任何变化,由此得知:

ByteBuffer 的order(ByteOrder.LITTLE_ENDIAN);这个方法只对非字节数组类型的变量有效。因为我们直接操作字节数组的时候,无论CPU如何存放,我们已经手动规定死了字节的存放顺序。所以这一方法无影响。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值