物联网类的系统开发,涉及与低功耗终端设备间的对接,经常会用到16进制之间转化问题,如byte[]转为16进制字符串,BCD码转字节数组等。本工具类依赖hutool,请注意先导入此包。
import cn.hutool.core.util.StrUtil;
import java.util.Base64;
import java.util.Locale;
public class HexConvertUtil {
/**
* 一个字节包含位的数量 8
*/
private static final int BITS_OF_BYTE = 8;
/**
* 多项式
*/
private static final int POLYNOMIAL = 0xA001;
/**
* 初始值
*/
private static final int INITIAL_VALUE = 0xFFFF;
private final static char[] mChars = "0123456789ABCDEF".toCharArray();
private final static String mHexStr = "0123456789ABCDEF";
/**
* 检查16进制字符串是否有效
*
* @param sHex String 16进制字符串
* @return boolean
*/
public static boolean checkHexStr(String sHex) {
String sTmp = sHex.trim().replace(" ", "").toUpperCase(Locale.US);
int iLen = sTmp.length();
if (iLen > 1 && iLen % 2 == 0) {
for (int i = 0; i < iLen; i++)
if (!mHexStr.contains(sTmp.substring(i, i + 1)))
return false;
return true;
} else
return false;
}
/**
* 字符串转换成十六进制字符串
*
* @param str String 待转换的ASCII字符串
* @return String 每个Byte之间空格分隔,如: [61 6C 6B]
*/
public static String str2HexStr(String str) {
StringBuilder sb = new StringBuilder();
byte[] bs = str.getBytes();
for (int i = 0; i < bs.length; i++) {
sb.append(mChars[(bs[i] & 0xFF) >> 4]);
sb.append(mChars[bs[i] & 0x0F]);
sb.append(' ');
}
return sb.toString().trim();
}
/**
* 十六进制字符串转换成 ASCII字符串
*
* @param hexStr String Byte字符串
* @return String 对应的字符串
*/
public static String hexStr2Str(String hexStr) {
hexStr = hexStr.trim().replace(" ", "").toUpperCase(Locale.US);
char[] hexs = hexStr.toCharArray();
byte[] bytes = new byte[hexStr.length() / 2];
int iTmp;
for (int i = 0; i < bytes.length; i++) {
iTmp = mHexStr.indexOf(hexs[2 * i]) << 4;
iTmp |= mHexStr.indexOf(hexs[2 * i + 1]);
bytes[i] = (byte) (iTmp & 0xFF);
}
return new String(bytes);
}
/**
* bytes转换成十六进制字符串
*
* @param b byte[] byte数组
* @param iLen int 取前N位处理 N=iLen
* @return String 每个Byte值之间空格分隔
*/
public static String byte2HexStr(byte[] b, int iLen) {
StringBuilder sb = new StringBuilder();
for (int n = 0; n < iLen; n++) {
sb.append(mChars[(b[n] & 0xFF) >> 4]);
sb.append(mChars[b[n] & 0x0F]);
sb.append(' ');
}
return sb.toString().trim().toUpperCase(Locale.US);
}
/**
* bytes字符串转换为Byte值
*
* @param src String Byte字符串,每个Byte之间没有分隔符(字符范围:0-9 A-F)
* @return byte[]
*/
public static byte[] hexStr2Bytes(String src) {
/*对输入值进行规范化整理*/
src = src.trim().replace(" ", "").toUpperCase(Locale.US);
//处理值初始化
int m, n;
int iLen = src.length() / 2; //计算长度
byte[] ret = new byte[iLen]; //分配存储空间
for (int i = 0; i < iLen; i++) {
m = i * 2 + 1;
n = m + 1;
ret[i] = (byte) (Integer.decode("0x" + src.substring(i * 2, m) + src.substring(m, n)) & 0xFF);
}
return ret;
}
/**
* String的字符串转换成unicode的String
*
* @param strText String 全角字符串
* @return String 每个unicode之间无分隔符
* @throws Exception
*/
public static String strToUnicode(String strText)
throws Exception {
char c;
StringBuilder str = new StringBuilder();
int intAsc;
String strHex;
for (int i = 0; i < strText.length(); i++) {
c = strText.charAt(i);
intAsc = (int) c;
strHex = Integer.toHexString(intAsc);
if (intAsc > 128)
str.append("\\u");
else // 低位在前面补00
str.append("\\u00");
str.append(strHex);
}
return str.toString();
}
/**
* unicode的String转换成String的字符串
*
* @param hex String 16进制值字符串 (一个unicode为2byte)
* @return String 全角字符串
*/
public static String unicodeToString(String hex) {
int t = hex.length() / 6;
int iTmp;
StringBuilder str = new StringBuilder();
for (int i = 0; i < t; i++) {
String s = hex.substring(i * 6, (i + 1) * 6);
// 将16进制的string转为int
iTmp = (Integer.valueOf(s.substring(2, 4), 16) << 8) | Integer.valueOf(s.substring(4), 16);
// 将int转换为字符
str.append(new String(Character.toChars(iTmp)));
}
return str.toString();
}
/**
* 将bytes转为16进制string
*
* @param byteArray
* @return
*/
public static String byteArrayToHexStr(byte[] byteArray) {
if (byteArray == null) {
return null;
}
char[] hexArray = "0123456789ABCDEF".toCharArray();
char[] hexChars = new char[byteArray.length * 2];
for (int j = 0; j < byteArray.length; j++) {
int v = byteArray[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
/**
* 将指定字符串src,以每两个字符分割转换为16进制形式
* 如:"2B44EFD9" --> byte[]{0x2B, 0x44, 0xEF, 0xD9}
*
* @param src String
* @return byte[]
*/
public static byte[] hexString2Bytes(String src) {
byte[] ret = new byte[src.length() / 2];
byte[] tmp = src.getBytes();
for (int i = 0; i < tmp.length / 2; i++) {
ret[i] = uniteBytes(tmp[i * 2], tmp[i * 2 + 1]);
}
return ret;
}
/**
* 将两个ASCII字符合成一个字节;
* 如:"EF"--> 0xEF
*
* @param src0 byte
* @param src1 byte
* @return byte
*/
public static byte uniteBytes(byte src0, byte src1) {
byte _b0 = Byte.decode("0x" + new String(new byte[]{src0})).byteValue();
_b0 = (byte) (_b0 << 4);
byte _b1 = Byte.decode("0x" + new String(new byte[]{src1})).byteValue();
byte ret = (byte) (_b0 ^ _b1);
return ret;
}
/**
* 拆分数组
*
* @param start 开始下标
* @param length 拆分长度
* @param bytes 需要拆分的数组
* @return
*/
public static byte[] split(int start, int length, byte[] bytes) {
byte[] by = new byte[length];
System.arraycopy(bytes, start, by, 0, length);
return by;
}
/**
* bytes转换成十六进制字符串 不带空格
*
* @param b byte数组
* @return String 每个Byte值之间空格分隔 如: 616C6B
*/
public static String bytes2HexStr1(byte[] b) {
String stmp;
StringBuilder sb = new StringBuilder("");
for (int n = 0; n < b.length; n++) {
stmp = Integer.toHexString(b[n] & 0xFF);
sb.append((stmp.length() == 1) ? "0" + stmp : stmp);
}
return sb.toString().toUpperCase().trim();
}
/**
* 将字节数组合并为字符串.<br>
* 本方法为取出每一位字节,直接作为字符处理,而不是作为ASCII值<br>
* 例如:字节49->字符49,而不是字节49->字符1(字符1的ASCII值是49)
*
* @param byteArray
* @return
*/
public static String byteArray2String(byte[] byteArray) {
// 合并后的字符串
StringBuffer sb = new StringBuffer(byteArray.length);
// 遍历字节数组
for (int i = 0, length = byteArray.length; i < length; i++) {
sb.append(byteArray[i]);
}
return sb.toString();
}
/**
* BCD码转字节数组
*
* @param bcd bcd码
* @return
*/
public static byte[] bcd2ByteArray(byte[] bcd) {
// 转换后字节数组
byte[] byteArray = new byte[bcd.length * 2];
// 遍历BCD码
for (int i = 0, length = bcd.length; i < length; i++) {
byteArray[i * 2] = (byte) ((bcd[i] & 0xf0) >> 4);
byteArray[i * 2 + 1] = (byte) (bcd[i] & 0x0f);
}
return byteArray;
}
/**
* 将字节数组(0<长度<=8)合并为长整型
*
* @param byteArray
* @return
*/
public static long byteArray2Long(byte[] byteArray) {
// 字节数组长度
int length = byteArray.length;
if (length == 0) {
throw new RuntimeException("运行异常");
} else if (length > 8) {
throw new RuntimeException("运行异常");
} else {
// 获取最末位的字节
long l = byte2Long(byteArray[length - 1]);
// 遍历字节数组,从倒数第二位向前
for (int index = length - 1; index > 0; index--) {
// 数组的第(index-1)位,要向左移(length-index)字节
l = l | byte2Long(byteArray[index - 1]) << ((length - index) * 8);
}
return l;
}
}
public static long byte2Long(byte b) {
return (b & 0xff);
}
/**
* 字节数组转为普通字符串(ASCII对应的字符)
*
* @param bytearray byte[]
* @return String
*/
public static String bytetoString(byte[] bytearray) {
String result = "";
char temp;
int length = bytearray.length;
for (int i = 0; i < length; i++) {
temp = (char) bytearray[i];
result += temp;
}
return result;
}
/**
* 将字节数组(0<长度<=4)合并为整型
*
* @param byteArray
* @return
*/
public static int byteArray2Int(byte[] byteArray) {
// 字节数组长度
int length = byteArray.length;
if (length == 0) {
throw new RuntimeException("运行异常");
} else if (length > 4) {
throw new RuntimeException("运行异常");
} else {
// 获取最末位的字节
int i = byte2Int(byteArray[length - 1]);
// 遍历字节数组,从倒数第二位向前
for (int index = length - 1; index > 0; index--) {
// 数组的第(index-1)位,要向左移(length-index)字节
i = i | (byte2Int(byteArray[index - 1]) << ((length - index) * 8));
}
return i;
}
}
/**
* 将无符号字节(即8位均为数据的字节)转换为有符号的整型;
*
* @param b 无符号字节
* @return
*/
public static int byte2Int(byte b) {
return (b & 0xff);
}
/**
* 字节数组转BCD码,字节数组长度必须为2的倍数
*
* @param byteArray
* @return
*/
public static byte[] byteArray2BCD(byte[] byteArray) {
// 字节数组长度
int byteArrayLength = byteArray.length;
// 若长度不为2的倍数,则抛出异常
if (byteArrayLength % 2 != 0) {
throw new RuntimeException("运行异常");
}
// BCD码
byte[] bcd = new byte[byteArrayLength / 2];
// 遍历字节数组
for (int i = 0, length = bcd.length; i < length; i++) {
// 前字节向左位移4位,与上后字节
bcd[i] = (byte) (((byte) (byteArray[i * 2] << 4)) | (byteArray[i * 2 + 1]));
}
return bcd;
}
/**
* 将字符串拆分为字节数组.
* 本方法为取出每一个字符,将其直接转为byte,而非使用ASCII值进行转换
* 例如:字符1->字节1,而不是字符1->字节49(字符1的ASCII值是49)
*
* @param str
* @return
*/
public static byte[] string2ByteArray(String str) {
// 拆分后的字节数组
byte[] byteArray = new byte[str.length()];
// 遍历字符串每一个字符
for (int i = 0, length = str.length(); i < length; i++) {
byteArray[i] = Byte.valueOf(str.charAt(i) + "");
}
return byteArray;
}
/**
* 将整型拆分为长度为4的字节数组
*
* @param i
* @return
*/
public static byte[] int2ByteArray(int i) {
// 拆分后的字节数组
byte[] byteArray = new byte[4];
// 数组长度
int length = byteArray.length;
// 遍历数组
for (int index = 1; index <= length; index++) {
// 数组的第(index-1)位,要向右移(length-index)字节
byteArray[index - 1] = (byte) (i >> ((length - index) * 8));
}
return byteArray;
}
/**
* 将长整型拆分为长度为8的字节数组
*
* @param l
* @return
*/
public static byte[] long2ByteArray(long l) {
// 拆分后的字节数组
byte[] byteArray = new byte[8];
// 数组长度
int length = byteArray.length;
// 遍历数组
for (int index = 1; index <= length; index++) {
// 数组的第(index-1)位,要向右移(length-index)字节
byteArray[index - 1] = (byte) (l >> ((length - index) * 8));
}
return byteArray;
}
public static byte[] intToBytes(int source, int length) {
byte[] b = new byte[length];
for (int i = 0; i < length; i++) {
b[i] = (byte) (source >> 8 * (length - i - 1) & 0xFF);
}
return b;
}
/**
* base64字符串转16进制字符串
*
* @param base64Str
* @return
*/
public static byte[] base64ToHexByte(String base64Str) {
if (StrUtil.isEmpty(base64Str)) {
throw new RuntimeException("base64字符串不能为空!");
}
return Base64.getDecoder().decode(base64Str);
}
public static String byteArrToBinStr(byte[] b) {
StringBuilder result = new StringBuilder();
for (byte value : b) {
String str = Long.toString(value & 0xff, 2);
if (str.length() < 8) {
StringBuilder zeroStr = new StringBuilder();
for (int i = 0; i < (8 - str.length()); i++) {
zeroStr.append(0);
}
str = zeroStr + str;
}
result.append(str).append(",");
}
return result.substring(0, result.length() - 1);
}
public static int crc16(byte[] bytes) {
int res = INITIAL_VALUE;
for (int data : bytes) {
res = res ^ data;
for (int i = 0; i < BITS_OF_BYTE; i++) {
res = (res & 0x0001) == 1 ? (res >> 1) ^ POLYNOMIAL : res >> 1;
}
}
return revert(res);
}
private static int revert(int src) {
int lowByte = (src & 0xFF00) >> 8;
int highByte = (src & 0x00FF) << 8;
return lowByte | highByte;
}
public static byte crc8(byte[] data) {
byte crc = 0;
for (byte datum : data) {
crc ^= datum;
for (int i = 0; i < 8; i++) {
if ((crc & 0x80) != 0) {
crc = (byte) ((crc) << 1);
crc ^= (byte) 0x107;
} else {
crc = (byte) ((crc) << 1);
}
}
}
return crc;
}
}