我有一个字节数组。 我希望将该数组的每个字节String转换为相应的十六进制值。
Java中是否有将字节数组转换为十六进制的函数?
我有一个字节数组。 我希望将该数组的每个字节String转换为相应的十六进制值。
Java中是否有将字节数组转换为十六进制的函数?
当前回答
只是添加我的两分,因为我看到许多答案使用字符数组和/或使用StringBuilder实例,并声称是快速或更快。
由于我使用ASCII表组织有一个不同的想法,代码点48-57为0-9,代码点65-70为a-f,代码点97-102为a-f,我想测试哪个想法是最快的。
因为我已经好几年没有做过类似的事情了,所以我要做一个广泛的拍摄。我在不同大小的数组中使用了10亿字节(1M, 1K, 10),因此每个数组有1000倍1M字节,每个数组有1M倍1000字节,每个数组有100M倍10字节。
结果是1-F中的char数组胜出。使用char数组而不是StringBuilder作为输出也很容易(对象更少,不需要测试容量,在增长时不需要新数组或复制)。此外,当使用foreach (for(var b: bytes))循环时,你似乎会得到一个小的惩罚。
使用我的想法的版本大约是。每个数组1M字节时慢15%,每个数组1000字节时慢21%,每个数组10字节时慢18%。StringBuilder版本分别慢了210%、380%和310%。
这很糟糕,但也不是那么出乎意料,因为在第一级缓存中查找小数组胜过if和add... .(一个缓存访问+偏移量计算vs.一个if,一个跳转,一个add ->不确定跳转thou)。
我的版本:
public static String bytesToHex(byte [] bytes) {
char [] result = new char [bytes.length * 2];
for(int index = 0; index < bytes.length; index++) {
int v = bytes[index];
int upper = (v >>> 4) & 0xF;
result[index * 2] = (char)(upper + (upper < 10 ? 48 : 65 - 10));
int lower = v & 0xF;
result[index * 2 + 1] = (char)(lower + (lower < 10 ? 48 : 65 - 10));
}
return new String(result);
}
PS:是的,我做了多次测试,每次都做了最好的测试,做了热身,也做了100亿字符的测试,以确保相同的图片... .
其他回答
byte[] bytes = {-1, 0, 1, 2, 3 };
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X ", b));
}
System.out.println(sb.toString());
// prints "FF 00 01 02 03 "
另请参阅
java.util.Formatter语法 %(旗帜)(宽度)转换 标记'0' -结果将被填充为零 宽度2 转换'X' -结果被格式化为十六进制整数,大写
看看问题的文本,也有可能是这样要求的:
String[] arr = {"-1", "0", "10", "20" };
for (int i = 0; i < arr.length; i++) {
arr[i] = String.format("%02x", Byte.parseByte(arr[i]));
}
System.out.println(java.util.Arrays.toString(arr));
// prints "[ff, 00, 0a, 14]"
这里的几个答案使用Integer.toHexString(int);这是可行的,但有一些注意事项。由于形参是int型,因此对byte参数执行扩大原语转换,这涉及到符号扩展。
byte b = -1;
System.out.println(Integer.toHexString(b));
// prints "ffffffff"
在Java中有符号的8位字节被符号扩展为32位整型。为了有效地撤销这个符号扩展,可以使用0xFF来屏蔽字节。
byte b = -1;
System.out.println(Integer.toHexString(b & 0xFF));
// prints "ff"
使用toHexString的另一个问题是它不会用零填充:
byte b = 10;
System.out.println(Integer.toHexString(b & 0xFF));
// prints "a"
这两个因素结合起来应该形成字符串。格式解决方案更佳。
参考文献
整型类型和值 对于字节,从-128到127,包括 JLS 5.1.2扩大原语转换
其他人已经报道了一般情况。但是如果你有一个已知形式的字节数组,例如MAC地址,那么你可以:
byte[] mac = { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 };
String str = String.format("%02X:%02X:%02X:%02X:%02X:%02X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
你可以使用Bouncy Castle Provider库中的方法:
org.bouncycastle.util.encoders.Hex.toHexString(byteArray);
Bouncy Castle Crypto包是一个Java实现 加密算法。这个jar包含JCE提供程序和 用于JDK 1.5的Bouncy Castle Cryptography API的轻量级API JDK 1.8。
Maven的依赖:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.60</version>
</dependency>
或来自Apache Commons Codec:
org.apache.commons.codec.binary.Hex.encodeHexString(byteArray);
Apache Commons Codec包包含简单的编码器和解码器 用于各种格式,如Base64和十六进制。除了 这些编码器和解码器被广泛使用,编解码器包也有 维护语音编码实用程序的集合。
Maven的依赖:
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.11</version>
</dependency>
下面是一个将字节转换为十六进制的简单函数
private static String convertToHex(byte[] data) {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < data.length; i++) {
int halfbyte = (data[i] >>> 4) & 0x0F;
int two_halfs = 0;
do {
if ((0 <= halfbyte) && (halfbyte <= 9))
buf.append((char) ('0' + halfbyte));
else
buf.append((char) ('a' + (halfbyte - 10)));
halfbyte = data[i] & 0x0F;
} while(two_halfs++ < 1);
}
return buf.toString();
}
如果你想要一个恒定宽度的十六进制表示,即0A而不是a,这样你就可以明确地恢复字节,尝试format():
StringBuilder result = new StringBuilder();
for (byte bb : byteArray) {
result.append(String.format("%02X", bb));
}
return result.toString();