package com.learning.forsocket.decodeencode;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
/*
* 一下代码是根据java socket tcp/ip编程书籍中对基本类型编码例子添加相关自己注释以及理解
*
*因主机CPU不同,不同的机器会出现高、低两种字节序问题
*Little endian:将低序字节存储在起始地址
*Big endian:将高序字节存储在起始地址
* JAVA是网络字节序 字节存储高字节序
*java中提供相应的方法 也可以通过移位来实现【列子中是高字节位存储例子可以通过修改顺序实现Little endian】
*
*/
public class BruteForceCoding {
private static byte byteVal = 101;
private static short shortVal = 10001;
private static int intVal = 100000001;
private static long longVal = 1000000000001L;
/**
* byte short int long 类型占用几个字节
* */
private final static int BSIZE = Byte.BYTES;
private final static int SSIZE = Short.BYTES;
private final static int ISIZE = Integer.BYTES;
private final static int LSIZE = Long.BYTES;
/*******
* 定义整数进行将无符号转成有符号的数据进行扩展位使用【主要针对一个字节来输出数据,方便观察数据】
*
*/
private final static int BYTEMASK = 0xFF;
/***
* 此方法的是将一个字节数据的数据以无符号十进制数据展示,主要方便我们观察存储数据
*
* **/
public static String byteArrayToDecimalString(byte[] bArray) {
StringBuilder rtn=new StringBuilder();
for (byte b : bArray) {
rtn.append(b&BYTEMASK).append(" ");
/***
* 这块的逻辑【有符号转负】:比如-128的数据【补码】 10000000--》-128的扩展为是11111111 11111111 11111111 10000000 与 00000000 00000000
* 00000000 11111111 做&运算 00000000 00000000 00000000 1000000--->即是128 -127-->对应129
* 也可以这样简单理解:1个字节 -128-127 如果变成无符号的一个字节大小就是0-255 由于数据数据是周期性127之后就是-128对应129 ...-1就是255
*/
}
return rtn.toString();
}
/****
*
* @param dst 字节数组
* @param val 数据
* @param offset 存的偏移量
* @param size 存放几个字节
* @return
*/
public static int encodeIntBigEndian(byte[]dst,long val,int offset,int size){
for (int i = 0; i < size; i++) {
//字节数组先存高位然后地位字节
dst[offset++]= (byte) (val>>((size-i-1)*Byte.SIZE));
}
return offset;//返回的数据表示字节数据的位置
}
/**
*
* @param val 字节数据
* @param offset 读取的开始字节数组位置
* @param size 几个字节
* @return
*/
public static long decodeIntBigEndian(byte[] val,int offset,int size){
long rtn=0;
for (int i = 0; i < size; i++) {
/**
*处理方式方式:第一次rtn=0,假设取两个字节 offset=1
* 首先去val[offset],第二个字节,首先rtn左移动8位,然后取val[offset+1] 取最后8位 做|运算
* 其他的计算依然如此
*/
rtn=(rtn<<Byte.SIZE)|((long)val[offset+i]&BYTEMASK);
}
return rtn;
}
/***
* 将有符号的字节转成int
* @param data
* @return
*/
public static int getUnsignedByte (byte data){
return data&0x0FF ;
}
public static void main(String[] args) throws Exception {
//
// byte sortdata=-1;
// System.out.println(getUnsignedByte(sortdata));
//定义一个字节数据
byte[] mesage=new byte[BSIZE+SSIZE+ISIZE+LSIZE];//1+2+4+8 15个字节
//编码 分别将 byte short int long类型的数据写入字节数据【超过1一个字节的数据类型 高位在前 低位在后】
int offset=encodeIntBigEndian(mesage,byteVal,0,BSIZE);
offset=encodeIntBigEndian(mesage,shortVal,offset,SSIZE);
offset=encodeIntBigEndian(mesage,intVal,offset,ISIZE);
offset=encodeIntBigEndian(mesage,longVal,offset,LSIZE);
System.out.println("Encode message:"+byteArrayToDecimalString(mesage));
//解码
long value=decodeIntBigEndian(mesage,0,BSIZE);
System.out.println("Docoded byte="+value);
value=decodeIntBigEndian(mesage,BSIZE,SSIZE);//从下标是1的位置开始读取2个字节
System.out.println("Docoded short="+value);
value=decodeIntBigEndian(mesage,3,ISIZE);//从下标是1的位置开始读取2个字节
System.out.println("Docoded int="+value);
value=decodeIntBigEndian(mesage,BSIZE+SSIZE+ISIZE,LSIZE);//从下标是7的位置开始读取8个字节
System.out.println("Docoded long="+value);
offset=4;
value=decodeIntBigEndian(mesage,offset,BSIZE);//表示取第五个字节取一个字节 245
System.out.println("Decoded value(offset "+offset+",size "+BSIZE+")="+value);
byte bVal=(byte)decodeIntBigEndian(mesage,offset,BSIZE);//-11
System.out.println("Same value as byte="+bVal);
/*java提供原声方法进行输出【高序字节】*/
ByteArrayOutputStream buf=new ByteArrayOutputStream();
DataOutputStream out=new DataOutputStream(buf);
out.writeByte(byteVal);
out.writeShort(shortVal);
out.writeInt(intVal);
out.writeLong(longVal);
out.flush();
byte[] msg=buf.toByteArray();
System.out.println("Encode message:"+byteArrayToDecimalString(msg));
}
}
===========================================================
Java提供的方法也是通过移位来实现的,debug跟进可以看到: