我有一个字节数组。 我希望将该数组的每个字节String转换为相应的十六进制值。
Java中是否有将字节数组转换为十六进制的函数?
我有一个字节数组。 我希望将该数组的每个字节String转换为相应的十六进制值。
Java中是否有将字节数组转换为十六进制的函数?
当前回答
就像其他答案一样,我建议使用String.format()和BigInteger。但是要将字节数组解释为大端二进制表示,而不是双补二进制表示(使用signum和不完全使用可能的十六进制值范围),请使用BigInteger(int signum, byte[] magnitude),而不是BigInteger(byte[] val)。
例如,对于长度为8的字节数组,使用:
String.format("%016X", new BigInteger(1,bytes))
优点:
前导零 没有符号 只有内置函数 只有一行代码
劣势:
也许有更有效的方法
例子:
byte[] bytes = new byte[8];
Random r = new Random();
System.out.println("big-endian | two's-complement");
System.out.println("-----------------|-----------------");
for (int i = 0; i < 10; i++) {
r.nextBytes(bytes);
System.out.print(String.format("%016X", new BigInteger(1,bytes)));
System.out.print(" | ");
System.out.print(String.format("%016X", new BigInteger(bytes)));
System.out.println();
}
示例输出:
big-endian | two's-complement
-----------------|-----------------
3971B56BC7C80590 | 3971B56BC7C80590
64D3C133C86CCBDC | 64D3C133C86CCBDC
B232EFD5BC40FA61 | -4DCD102A43BF059F
CD350CC7DF7C9731 | -32CAF338208368CF
82CDC9ECC1BC8EED | -7D3236133E437113
F438C8C34911A7F5 | -BC7373CB6EE580B
5E99738BE6ACE798 | 5E99738BE6ACE798
A565FE5CE43AA8DD | -5A9A01A31BC55723
032EBA783D2E9A9F | 032EBA783D2E9A9F
8FDAA07263217ABA | -70255F8D9CDE8546
其他回答
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扩大原语转换
如果您乐于使用外部库,则org.apache.commons.codec.binary.Hex类有一个encodeHex方法,该方法接受一个字节[]并返回一个char[]。这个方法比format选项快得多,并且封装了转换的细节。还附带了一个decodeHex方法,用于相反的转换。
这是一条非常快的路。不需要外部库。
final protected static char[] HEXARRAY = "0123456789abcdef".toCharArray();
public static String encodeHexString( byte[] bytes ) {
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = HEXARRAY[v >>> 4];
hexChars[j * 2 + 1] = HEXARRAY[v & 0x0F];
}
return new String(hexChars);
}
最好的解决方案是这样的一句话:
String hex=DatatypeConverter.printHexBinary(byte[] b);
正如这里提到的
使用BigInteger将byte[]转换为十六进制字符串的简单方法:
import java.math.BigInteger;
byte[] bytes = new byte[] {(byte)255, 10, 20, 30};
String hex = new BigInteger(1, bytes).toString(16);
System.out.println(hex); // ff0a141e
它是如何工作的?
内置的系统类java.math.BigInteger类(java.math.BigInteger)兼容二进制和十六进制数据:
它有一个构造函数BigInteger(signum=1, byte[])通过byte[]创建一个大整数(设置它的第一个参数signum=1以正确处理负字节) 使用BigInteger.toString(16)将大整数转换为十六进制字符串 要解析十六进制数,请使用new BigInteger("ffa74b", 16) -不能正确处理前导零
如果你想在十六进制结果中有前导零,检查它的大小,并在必要时添加缺少的零:
if (hex.length() % 2 == 1)
hex = "0" + hex;
笔记
使用new BigInteger(1, bytes),而不是new BigInteger(bytes),因为Java“被设计破坏了”,字节数据类型不包含字节,而是有符号的小整数[-128…127]。如果第一个字节是负的,BigInteger假设您传递了一个负的大整数。只需传递1作为第一个参数(signum=1)。
从十六进制转换回字节[]是棘手的:有时前导零进入产生的输出,它应该像这样被清除:
byte[] bytes = new BigInteger("ffa74b", 16).toByteArray();
if (bytes[0] == 0) {
byte[] newBytes = new byte[bytes.length - 1];
System.arraycopy(bytes, 1, newBytes, 0, newBytes.length);
bytes = newBytes;
}
最后一个提示是如果字节[]有几个前导零,它们将丢失。